diff --git a/0001-Fix-pvops-Xen-detection-for-arm-machine.patch b/0001-Fix-pvops-Xen-detection-for-arm-machine.patch deleted file mode 100644 index 7b6b2363c14b09f92141dec268d9fdd5c2aa5287..0000000000000000000000000000000000000000 --- a/0001-Fix-pvops-Xen-detection-for-arm-machine.patch +++ /dev/null @@ -1,70 +0,0 @@ -From 5c4f786450ea61b87d4db0092288df83dd5cb454 Mon Sep 17 00:00:00 2001 -From: Qi Zheng -Date: Tue, 21 Dec 2021 15:40:31 +0800 -Subject: [PATCH 01/11] Fix pvops Xen detection for arm machine - -Since the xen_start_info on the arm/arm64 platform points to a static -variable '_xen_start_info'(see its definition as below), which makes -that the address of xen_start_info will never be null. - -arch/arm/xen/enlighten.c:40:static struct start_info _xen_start_info; -arch/arm/xen/enlighten.c:41:struct start_info *xen_start_info = &_xen_start_info; -arch/arm/xen/enlighten.c:42:EXPORT_SYMBOL(xen_start_info); - -As a result, the is_pvops_xen() in commit 4badc6229c69 ("Fix pvops -Xen detection for kernels >= v4.20") always returns TRUE because it -can always read out the non-null address of xen_start_info, finally -the following error will be reported on arm/arm64 platform(non-Xen -environment) because p2m_mid_missing and xen_p2m_addr are not defined: - - crash: cannot resolve "p2m_top" - -For the arm/arm64 platform, fix it by using xen_vcpu_info instead of -xen_start_info to detect Xen dumps. - -In addition, also explicitly narrow the scope of the xen_start_info -check to x86 with the machine_type(), there is no need to check it on -other architectures. - -Fixes: 4badc6229c69 ("Fix pvops Xen detection for kernels >= v4.20") -Signed-off-by: Qi Zheng -Acked-by: Kazuhito Hagio -Signed-off-by: Lianbo Jiang ---- - kernel.c | 20 +++++++++++++++----- - 1 file changed, 15 insertions(+), 5 deletions(-) - -diff --git a/kernel.c b/kernel.c -index 8ae9e0c169ff..a637dd0eb8f8 100644 ---- a/kernel.c -+++ b/kernel.c -@@ -10754,11 +10754,21 @@ is_pvops_xen(void) - STREQ(sym, "paravirt_patch_default"))) - return TRUE; - -- if (symbol_exists("xen_start_info") && -- readmem(symbol_value("xen_start_info"), KVADDR, &addr, -- sizeof(void *), "xen_start_info", RETURN_ON_ERROR) && -- addr != 0) -- return TRUE; -+ if (machine_type("X86") || machine_type("X86_64")) { -+ if (symbol_exists("xen_start_info") && -+ readmem(symbol_value("xen_start_info"), KVADDR, &addr, -+ sizeof(void *), "xen_start_info", RETURN_ON_ERROR) && -+ addr != 0) -+ return TRUE; -+ } -+ -+ if (machine_type("ARM") || machine_type("ARM64")) { -+ if (symbol_exists("xen_vcpu_info") && -+ readmem(symbol_value("xen_vcpu_info"), KVADDR, &addr, -+ sizeof(void *), "xen_vcpu_info", RETURN_ON_ERROR) && -+ addr != 0) -+ return TRUE; -+ } - - return FALSE; - } --- -2.20.1 - diff --git a/0001-LoongArch64-Add-kaslr-command-line-option-support.patch b/0001-LoongArch64-Add-kaslr-command-line-option-support.patch new file mode 100644 index 0000000000000000000000000000000000000000..3773dc13ed6955452a4b199343d946884979fe62 --- /dev/null +++ b/0001-LoongArch64-Add-kaslr-command-line-option-support.patch @@ -0,0 +1,107 @@ +From 0c3fc058e027a550dd9103c7d92e0802c1a2c1cb Mon Sep 17 00:00:00 2001 +From: Youling Tang +Date: Thu, 3 Mar 2022 14:41:14 +0800 +Subject: [PATCH 1/3] LoongArch64: Add "--kaslr" command line option support + +Apply initial changes to support kernel address space layout +randomization (KASLR) for loongarch64. This is the minimal patch +required to process loongarch64 dumps for the kernels configured +with CONFIG_RANDOMIZE_BASE(CONFIG_RELOCATABLE), and to accept the +"--kaslr" command line option. Only dumpfiles whose headers contain +kernel VMCOREINFO data are supported. + +Example: + # crash vmcore vmlinux --kaslr auto + +Change-Id: Ie0cff2ba38fc40cad07da6b183291805e0b17642 +Signed-off-by: Youling Tang +--- + crash.8 | 2 +- + help.c | 9 +++++---- + main.c | 3 ++- + symbols.c | 8 +++++--- + 4 files changed, 13 insertions(+), 9 deletions(-) + +diff --git a/crash.8 b/crash.8 +index 5020ce1..50c1c15 100644 +--- a/crash.8 ++++ b/crash.8 +@@ -487,7 +487,7 @@ command, search for their object files in + standard location that is compiled into the debuginfo data. + .TP + .BI --kaslr \ offset | auto +-If an x86_64 kernel was configured with ++If an x86, x86_64, s390x or loongarch64 kernel was configured with + .B CONFIG_RANDOMIZE_BASE, + the offset value is equal to the difference between the symbol values + compiled into the vmlinux file and their relocated KASLR values. If set to +diff --git a/help.c b/help.c +index ba56a1d..c8cca08 100644 +--- a/help.c ++++ b/help.c +@@ -336,10 +336,11 @@ char *program_usage_info[] = { + " and verification. The default count is 32768.", + "", + " --kaslr offset | auto", +- " If x86, x86_64 or s390x kernel was configured with CONFIG_RANDOMIZE_BASE,", +- " the offset value is equal to the difference between the symbol values ", +- " compiled into the vmlinux file and their relocated KASLR value. If", +- " set to auto, the KASLR offset value will be automatically calculated.", ++ " If x86, x86_64, s390x or loongarch64 kernel was configured with", ++ " CONFIG_RANDOMIZE_BASE, the offset value is equal to the difference", ++ " between the symbol values compiled into the vmlinux file and their", ++ " relocated KASLR value. If set to auto, the KASLR offset value will", ++ " be automatically calculated.", + "", + " --minimal", + " Bring up a session that is restricted to the log, dis, rd, sym,", +diff --git a/main.c b/main.c +index 71c59d2..80dd8dc 100644 +--- a/main.c ++++ b/main.c +@@ -228,7 +228,8 @@ main(int argc, char **argv) + } else if (STREQ(long_options[option_index].name, "kaslr")) { + if (!machine_type("X86_64") && + !machine_type("ARM64") && !machine_type("X86") && +- !machine_type("S390X")) ++ !machine_type("S390X") && ++ !machine_type("LOONGARCH64")) + error(INFO, "--kaslr not valid " + "with this machine type.\n"); + else if (STREQ(optarg, "auto")) +diff --git a/symbols.c b/symbols.c +index 695a86a..41bf9c6 100644 +--- a/symbols.c ++++ b/symbols.c +@@ -593,7 +593,8 @@ kaslr_init(void) + char *string; + + if ((!machine_type("X86_64") && !machine_type("ARM64") && !machine_type("X86") && +- !machine_type("S390X")) || (kt->flags & RELOC_SET)) ++ !machine_type("S390X") && !machine_type("LOONGARCH64")) || ++ (kt->flags & RELOC_SET)) + return; + + if (!kt->vmcoreinfo._stext_SYMBOL && +@@ -759,7 +760,7 @@ store_symbols(bfd *abfd, int dynamic, void *minisyms, long symcount, + } else if (!(kt->flags & RELOC_SET)) + kt->flags |= RELOC_FORCE; + } else if (machine_type("X86_64") || machine_type("ARM64") || +- machine_type("S390X")) { ++ machine_type("S390X") || machine_type("LOONGARCH64")) { + if ((kt->flags2 & RELOC_AUTO) && !(kt->flags & RELOC_SET)) + derive_kaslr_offset(abfd, dynamic, from, + fromend, size, store); +@@ -830,7 +831,8 @@ store_sysmap_symbols(void) + strerror(errno)); + + if (!machine_type("X86") && !machine_type("X86_64") && +- !machine_type("ARM64") && !machine_type("S390X")) ++ !machine_type("ARM64") && !machine_type("S390X") && ++ !machine_type("LOONGARCH64")) + kt->flags &= ~RELOC_SET; + + first = 0; +-- +2.20.1 + diff --git a/0001-LoongArch64-Do-not-verify-temporary-symbols-generate.patch b/0001-LoongArch64-Do-not-verify-temporary-symbols-generate.patch new file mode 100644 index 0000000000000000000000000000000000000000..db5469488dcc18fc8864be68f4cc9d8f15070f61 --- /dev/null +++ b/0001-LoongArch64-Do-not-verify-temporary-symbols-generate.patch @@ -0,0 +1,35 @@ +From 6deec92b158bc176d0d38cffa4e791af550c1a0a Mon Sep 17 00:00:00 2001 +From: Youling Tang +Date: Thu, 12 Jan 2023 15:12:57 +0800 +Subject: [PATCH] LoongArch64: Do not verify temporary symbols generated by + modules + +Do not verify the temporary symbols generated by the module to solve the +problem of entering the command line after a long time. + +Change-Id: I40a9387d92466ab110ad5fffa4de028f18bd3441 +Signed-off-by: Youling Tang +--- + symbols.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/symbols.c b/symbols.c +index d260236..6a376b0 100644 +--- a/symbols.c ++++ b/symbols.c +@@ -2400,9 +2400,11 @@ store_module_kallsyms_v2(struct load_module *lm, int start, int curr, + /* + * On ARM/ARM64 we have linker mapping symbols like '$a' + * or '$x' for ARM64, and '$d'. ++ * On LoongArch we have linker mapping symbols like '.L' ++ * or 'L0'. + * Make sure that these don't end up into our symbol list. + */ +- if ((machine_type("ARM") || machine_type("ARM64")) && ++ if ((machine_type("ARM") || machine_type("ARM64") || machine_type("LOONGARCH64")) && + !machdep->verify_symbol(nameptr, ec->st_value, ec->st_info)) + continue; + +-- +2.20.1 + diff --git a/0001-arm64-Support-overflow-stack-panic.patch b/0001-arm64-Support-overflow-stack-panic.patch deleted file mode 100644 index e8cb3acafc11046c81f16412ee43e3e5983a26fb..0000000000000000000000000000000000000000 --- a/0001-arm64-Support-overflow-stack-panic.patch +++ /dev/null @@ -1,379 +0,0 @@ -From c05db8d7d83389a342664073547bd29eda900158 Mon Sep 17 00:00:00 2001 -From: Hong YANG -Date: Mon, 15 Nov 2021 15:41:01 +0800 -Subject: [PATCH 1/2] arm64: Support overflow stack panic - -Kernel commit <872d8327ce89> ("arm64: add VMAP_STACK overflow detection") -has supported the overflow stack exception handling. Without the patch, the -"bt" command will make crash generate a core dump because of segmentation -fault. With the patch, the "bt" command can display the overflow stack. - -Before: -crash> bt -PID: 3607 TASK: ffffffcbf9a4da00 CPU: 2 COMMAND: "sh" -Segmentation fault (core dumped) - -After: -crash> bt -PID: 3607 TASK: ffffffcbf9a4da00 CPU: 2 COMMAND: "sh" - #0 [ffffffccbfd85f50] __delay at ffffff8008ceded8 -... - #5 [ffffffccbfd85fd0] emergency_restart at ffffff80080d49fc - #6 [ffffffccbfd86140] panic at ffffff80080af4c0 - #7 [ffffffccbfd86150] nmi_panic at ffffff80080af150 - #8 [ffffffccbfd86190] handle_bad_stack at ffffff800808b0b8 - #9 [ffffffccbfd862d0] __bad_stack at ffffff800808285c - PC: ffffff8008082e80 [el1_sync] - LR: ffffff8000d6c214 [stack_overflow_demo+84] - SP: ffffff1a79930070 PSTATE: 204003c5 - X29: ffffff8011b03d00 X28: ffffffcbf9a4da00 X27: ffffff8008e02000 - X26: 0000000000000040 X25: 0000000000000124 X24: ffffffcbf9a4da00 - X23: 0000007daec2e288 X22: ffffffcbfe03b800 X21: 0000007daec2e288 - X20: 0000000000000002 X19: 0000000000000002 X18: 0000000000000002 - X17: 00000000000003e7 X16: 0000000000000000 X15: 0000000000000000 - X14: ffffffcc17facb00 X13: ffffffccb4c25c00 X12: 0000000000000000 - X11: ffffffcc17fad660 X10: 0000000000000af0 X9: 0000000000000000 - X8: ffffff1a799334f0 X7: 0000000000000000 X6: 000000000000003f - X5: 0000000000000040 X4: 0000000000000010 X3: 00000065981d07f0 - X2: 00000065981d07f0 X1: 0000000000000000 X0: ffffff1a799334f0 - -Signed-off-by: Hong YANG ---- - arm64.c | 169 ++++++++++++++++++++++++++++++++++++++++++++++++++------ - defs.h | 6 ++ - 2 files changed, 159 insertions(+), 16 deletions(-) - -diff --git a/arm64.c b/arm64.c -index 94681d1a37db..23c3d75d85aa 100644 ---- a/arm64.c -+++ b/arm64.c -@@ -45,6 +45,7 @@ static int arm64_vtop_3level_4k(ulong, ulong, physaddr_t *, int); - static int arm64_vtop_4level_4k(ulong, ulong, physaddr_t *, int); - static ulong arm64_get_task_pgd(ulong); - static void arm64_irq_stack_init(void); -+static void arm64_overflow_stack_init(void); - static void arm64_stackframe_init(void); - static int arm64_eframe_search(struct bt_info *); - static int arm64_is_kernel_exception_frame(struct bt_info *, ulong); -@@ -63,6 +64,7 @@ static int arm64_get_dumpfile_stackframe(struct bt_info *, struct arm64_stackfra - static int arm64_in_kdump_text(struct bt_info *, struct arm64_stackframe *); - static int arm64_in_kdump_text_on_irq_stack(struct bt_info *); - static int arm64_switch_stack(struct bt_info *, struct arm64_stackframe *, FILE *); -+static int arm64_switch_stack_from_overflow(struct bt_info *, struct arm64_stackframe *, FILE *); - static int arm64_get_stackframe(struct bt_info *, struct arm64_stackframe *); - static void arm64_get_stack_frame(struct bt_info *, ulong *, ulong *); - static void arm64_gen_hidden_frame(struct bt_info *bt, ulong, struct arm64_stackframe *); -@@ -78,8 +80,11 @@ static int arm64_get_smp_cpus(void); - static void arm64_clear_machdep_cache(void); - static int arm64_on_process_stack(struct bt_info *, ulong); - static int arm64_in_alternate_stack(int, ulong); -+static int arm64_in_alternate_stackv(int cpu, ulong stkptr, ulong *stacks, ulong stack_size); - static int arm64_on_irq_stack(int, ulong); -+static int arm64_on_overflow_stack(int, ulong); - static void arm64_set_irq_stack(struct bt_info *); -+static void arm64_set_overflow_stack(struct bt_info *); - static void arm64_set_process_stack(struct bt_info *); - static int arm64_get_kvaddr_ranges(struct vaddr_range *); - static void arm64_get_crash_notes(void); -@@ -463,6 +468,7 @@ arm64_init(int when) - machdep->hz = 100; - - arm64_irq_stack_init(); -+ arm64_overflow_stack_init(); - arm64_stackframe_init(); - break; - -@@ -1715,6 +1721,49 @@ arm64_irq_stack_init(void) - } - } - -+/* -+ * Gather Overflow stack values. -+ * -+ * Overflow stack supported since 4.14, in commit 872d8327c -+ */ -+static void -+arm64_overflow_stack_init(void) -+{ -+ int i; -+ struct syment *sp; -+ struct gnu_request request, *req; -+ struct machine_specific *ms = machdep->machspec; -+ req = &request; -+ -+ if (symbol_exists("overflow_stack") && -+ (sp = per_cpu_symbol_search("overflow_stack")) && -+ get_symbol_type("overflow_stack", NULL, req)) { -+ if (CRASHDEBUG(1)) { -+ fprintf(fp, "overflow_stack: \n"); -+ fprintf(fp, " type: %x, %s\n", -+ (int)req->typecode, -+ (req->typecode == TYPE_CODE_ARRAY) ? -+ "TYPE_CODE_ARRAY" : "other"); -+ fprintf(fp, " target_typecode: %x, %s\n", -+ (int)req->target_typecode, -+ req->target_typecode == TYPE_CODE_INT ? -+ "TYPE_CODE_INT" : "other"); -+ fprintf(fp, " target_length: %ld\n", -+ req->target_length); -+ fprintf(fp, " length: %ld\n", req->length); -+ } -+ -+ if (!(ms->overflow_stacks = (ulong *)malloc((size_t)(kt->cpus * sizeof(ulong))))) -+ error(FATAL, "cannot malloc overflow_stack addresses\n"); -+ -+ ms->overflow_stack_size = ARM64_OVERFLOW_STACK_SIZE; -+ machdep->flags |= OVERFLOW_STACKS; -+ -+ for (i = 0; i < kt->cpus; i++) -+ ms->overflow_stacks[i] = kt->__per_cpu_offset[i] + sp->value; -+ } -+} -+ - /* - * Gather and verify all of the backtrace requirements. - */ -@@ -1960,6 +2009,7 @@ static char *arm64_exception_functions[] = { - "do_mem_abort", - "do_el0_irq_bp_hardening", - "do_sp_pc_abort", -+ "handle_bad_stack", - NULL - }; - -@@ -1978,7 +2028,10 @@ arm64_in_exception_text(ulong ptr) - if ((ptr >= ms->__exception_text_start) && - (ptr < ms->__exception_text_end)) - return TRUE; -- } else if ((name = closest_symbol(ptr))) { /* Linux 5.5 and later */ -+ } -+ -+ name = closest_symbol(ptr); -+ if (name != NULL) { /* Linux 5.5 and later */ - for (func = &arm64_exception_functions[0]; *func; func++) { - if (STREQ(name, *func)) - return TRUE; -@@ -2252,15 +2305,14 @@ arm64_unwind_frame(struct bt_info *bt, struct arm64_stackframe *frame) - if ((frame->fp == 0) && (frame->pc == 0)) - return FALSE; - -- if (!(machdep->flags & IRQ_STACKS)) -- return TRUE; -- -- if (!(machdep->flags & IRQ_STACKS)) -+ if (!(machdep->flags & (IRQ_STACKS | OVERFLOW_STACKS))) - return TRUE; - - if (machdep->flags & UNW_4_14) { -- if ((bt->flags & BT_IRQSTACK) && -- !arm64_on_irq_stack(bt->tc->processor, frame->fp)) { -+ if (((bt->flags & BT_IRQSTACK) && -+ !arm64_on_irq_stack(bt->tc->processor, frame->fp)) || -+ ((bt->flags & BT_OVERFLOW_STACK) && -+ !arm64_on_overflow_stack(bt->tc->processor, frame->fp))) { - if (arm64_on_process_stack(bt, frame->fp)) { - arm64_set_process_stack(bt); - -@@ -2677,6 +2729,9 @@ arm64_back_trace_cmd(struct bt_info *bt) - if (arm64_on_irq_stack(bt->tc->processor, bt->frameptr)) { - arm64_set_irq_stack(bt); - bt->flags |= BT_IRQSTACK; -+ } else if (arm64_on_overflow_stack(bt->tc->processor, bt->frameptr)) { -+ arm64_set_overflow_stack(bt); -+ bt->flags |= BT_OVERFLOW_STACK; - } - stackframe.sp = bt->stkptr; - stackframe.pc = bt->instptr; -@@ -2731,7 +2786,9 @@ arm64_back_trace_cmd(struct bt_info *bt) - break; - - if (arm64_in_exception_text(bt->instptr) && INSTACK(stackframe.fp, bt)) { -- if (!(bt->flags & BT_IRQSTACK) || -+ if (bt->flags & BT_OVERFLOW_STACK) { -+ exception_frame = stackframe.fp - KERN_EFRAME_OFFSET; -+ } else if (!(bt->flags & BT_IRQSTACK) || - ((stackframe.sp + SIZE(pt_regs)) < bt->stacktop)) { - if (arm64_is_kernel_exception_frame(bt, stackframe.fp - KERN_EFRAME_OFFSET)) - exception_frame = stackframe.fp - KERN_EFRAME_OFFSET; -@@ -2745,6 +2802,12 @@ arm64_back_trace_cmd(struct bt_info *bt) - break; - } - -+ if ((bt->flags & BT_OVERFLOW_STACK) && -+ !arm64_on_overflow_stack(bt->tc->processor, stackframe.fp)) { -+ bt->flags &= ~BT_OVERFLOW_STACK; -+ if (arm64_switch_stack_from_overflow(bt, &stackframe, ofp) == USER_MODE) -+ break; -+ } - - level++; - } -@@ -3131,6 +3194,43 @@ arm64_switch_stack(struct bt_info *bt, struct arm64_stackframe *frame, FILE *ofp - return KERNEL_MODE; - } - -+static int -+arm64_switch_stack_from_overflow(struct bt_info *bt, struct arm64_stackframe *frame, FILE *ofp) -+{ -+ int i; -+ ulong stacktop, words, addr; -+ ulong *stackbuf; -+ char buf[BUFSIZE]; -+ struct machine_specific *ms = machdep->machspec; -+ -+ if (bt->flags & BT_FULL) { -+ stacktop = ms->overflow_stacks[bt->tc->processor] + ms->overflow_stack_size; -+ words = (stacktop - bt->bptr) / sizeof(ulong); -+ stackbuf = (ulong *)GETBUF(words * sizeof(ulong)); -+ readmem(bt->bptr, KVADDR, stackbuf, words * sizeof(long), -+ "top of overflow stack", FAULT_ON_ERROR); -+ -+ addr = bt->bptr; -+ for (i = 0; i < words; i++) { -+ if (!(i & 1)) -+ fprintf(ofp, "%s %lx: ", i ? "\n" : "", addr); -+ fprintf(ofp, "%s ", format_stack_entry(bt, buf, stackbuf[i], 0)); -+ addr += sizeof(ulong); -+ } -+ fprintf(ofp, "\n"); -+ FREEBUF(stackbuf); -+ } -+ fprintf(ofp, "--- ---\n"); -+ -+ if (frame->fp == 0) -+ return USER_MODE; -+ -+ if (!(machdep->flags & UNW_4_14)) -+ arm64_print_exception_frame(bt, frame->sp, KERNEL_MODE, ofp); -+ -+ return KERNEL_MODE; -+} -+ - static int - arm64_get_dumpfile_stackframe(struct bt_info *bt, struct arm64_stackframe *frame) - { -@@ -3682,6 +3782,16 @@ arm64_display_machine_stats(void) - machdep->machspec->irq_stacks[i]); - } - } -+ if (machdep->machspec->overflow_stack_size) { -+ fprintf(fp, "OVERFLOW STACK SIZE: %ld\n", -+ machdep->machspec->overflow_stack_size); -+ fprintf(fp, " OVERFLOW STACKS:\n"); -+ for (i = 0; i < kt->cpus; i++) { -+ pad = (i < 10) ? 3 : (i < 100) ? 2 : (i < 1000) ? 1 : 0; -+ fprintf(fp, "%s CPU %d: %lx\n", space(pad), i, -+ machdep->machspec->overflow_stacks[i]); -+ } -+ } - } - - static int -@@ -3875,24 +3985,41 @@ arm64_on_process_stack(struct bt_info *bt, ulong stkptr) - } - - static int --arm64_on_irq_stack(int cpu, ulong stkptr) -+arm64_in_alternate_stackv(int cpu, ulong stkptr, ulong *stacks, ulong stack_size) - { -- return arm64_in_alternate_stack(cpu, stkptr); -+ if ((cpu >= kt->cpus) || (stacks == NULL) || !stack_size) -+ return FALSE; -+ -+ if ((stkptr >= stacks[cpu]) && -+ (stkptr < (stacks[cpu] + stack_size))) -+ return TRUE; -+ -+ return FALSE; - } - - static int - arm64_in_alternate_stack(int cpu, ulong stkptr) -+{ -+ return (arm64_on_irq_stack(cpu, stkptr) || -+ arm64_on_overflow_stack(cpu, stkptr)); -+} -+ -+static int -+arm64_on_irq_stack(int cpu, ulong stkptr) - { - struct machine_specific *ms = machdep->machspec; - -- if (!ms->irq_stack_size || (cpu >= kt->cpus)) -- return FALSE; -+ return arm64_in_alternate_stackv(cpu, stkptr, -+ ms->irq_stacks, ms->irq_stack_size); -+} - -- if ((stkptr >= ms->irq_stacks[cpu]) && -- (stkptr < (ms->irq_stacks[cpu] + ms->irq_stack_size))) -- return TRUE; -+static int -+arm64_on_overflow_stack(int cpu, ulong stkptr) -+{ -+ struct machine_specific *ms = machdep->machspec; - -- return FALSE; -+ return arm64_in_alternate_stackv(cpu, stkptr, -+ ms->overflow_stacks, ms->overflow_stack_size); - } - - static void -@@ -3905,6 +4032,16 @@ arm64_set_irq_stack(struct bt_info *bt) - alter_stackbuf(bt); - } - -+static void -+arm64_set_overflow_stack(struct bt_info *bt) -+{ -+ struct machine_specific *ms = machdep->machspec; -+ -+ bt->stackbase = ms->overflow_stacks[bt->tc->processor]; -+ bt->stacktop = bt->stackbase + ms->overflow_stack_size; -+ alter_stackbuf(bt); -+} -+ - static void - arm64_set_process_stack(struct bt_info *bt) - { -diff --git a/defs.h b/defs.h -index 43eff46b105d..caaa11e50c87 100644 ---- a/defs.h -+++ b/defs.h -@@ -3218,6 +3218,7 @@ typedef signed int s32; - #define UNW_4_14 (0x200) - #define FLIPPED_VM (0x400) - #define HAS_PHYSVIRT_OFFSET (0x800) -+#define OVERFLOW_STACKS (0x1000) - - /* - * Get kimage_voffset from /dev/crash -@@ -3260,6 +3261,7 @@ typedef signed int s32; - - #define ARM64_STACK_SIZE (16384) - #define ARM64_IRQ_STACK_SIZE ARM64_STACK_SIZE -+#define ARM64_OVERFLOW_STACK_SIZE (4096) - - #define _SECTION_SIZE_BITS 30 - #define _SECTION_SIZE_BITS_5_12 27 -@@ -3332,6 +3334,9 @@ struct machine_specific { - char *irq_stackbuf; - ulong __irqentry_text_start; - ulong __irqentry_text_end; -+ ulong overflow_stack_size; -+ ulong *overflow_stacks; -+ char *overflow_stackbuf; - /* for exception vector code */ - ulong exp_entry1_start; - ulong exp_entry1_end; -@@ -5778,6 +5783,7 @@ ulong cpu_map_addr(const char *type); - #define BT_CPUMASK (0x1000000000000ULL) - #define BT_SHOW_ALL_REGS (0x2000000000000ULL) - #define BT_REGS_NOT_FOUND (0x4000000000000ULL) -+#define BT_OVERFLOW_STACK (0x8000000000000ULL) - #define BT_SYMBOL_OFFSET (BT_SYMBOLIC_ARGS) - - #define BT_REF_HEXVAL (0x1) --- -2.30.2 - diff --git a/0001-crash-Add-LoongArch-support.patch b/0001-crash-Add-LoongArch-support.patch deleted file mode 100644 index 3c120e5730f982a7b895aa62640f9598732c876b..0000000000000000000000000000000000000000 --- a/0001-crash-Add-LoongArch-support.patch +++ /dev/null @@ -1,7601 +0,0 @@ -From ee53b97eed4b0d808aced7e22da69ad9b8eb79d1 Mon Sep 17 00:00:00 2001 -From: Youling Tang -Date: Tue, 12 Jul 2022 10:40:46 +0800 -Subject: [PATCH] crash: Add LoongArch support - -Signed-off-by: Youling Tang ---- - .gitignore | 1 - - Makefile | 16 +- - README | 4 +- - configure.c | 55 +- - crash_target.c | 135 + - defs.h | 252 +- - diskdump.c | 39 +- - gdb-7.6-proc_service.h.patch | 67 - - gdb-7.6.patch | 2558 ----------------- - ...ort.patch => gdb-8.1-ppc64le-support.patch | 0 - gdb-8.1.patch | 1615 +++++++++++ - gdb_interface.c | 108 +- - help.c | 5 +- - kernel.c | 2 +- - lkcd_vmdump_v1.h | 2 + - lkcd_vmdump_v2_v3.h | 4 +- - loongarch64.c | 1344 +++++++++ - main.c | 1 - - netdump.c | 39 +- - ramdump.c | 2 + - sadump.c | 2 +- - symbols.c | 114 +- - tools.c | 2 +- - vmware_guestdump.c | 5 + - vmware_vmss.c | 60 +- - x86_64.c | 30 +- - 27 files changed, 3671 insertions(+), 2814 deletions(-) - create mode 100644 crash_target.c - delete mode 100644 gdb-7.6-proc_service.h.patch - delete mode 100644 gdb-7.6.patch - rename gdb-7.6-ppc64le-support.patch => gdb-8.1-ppc64le-support.patch (100%) - create mode 100644 gdb-8.1.patch - create mode 100644 loongarch64.c - -diff --git a/.gitignore b/.gitignore -index b39832f..ea72c5b 100644 ---- a/.gitignore -+++ b/.gitignore -@@ -7,7 +7,6 @@ crash - CFLAGS.extra - LDFLAGS.extra - crash.spec --*.gz - *.rpm - gdb.files - gdb-7.6/ -diff --git a/Makefile b/Makefile -index eae023c..5c70275 100644 ---- a/Makefile -+++ b/Makefile -@@ -63,7 +63,7 @@ CFILES=main.c tools.c global_data.c memory.c filesys.c help.c task.c \ - kernel.c test.c gdb_interface.c configure.c net.c dev.c bpf.c \ - printk.c \ - alpha.c x86.c ppc.c ia64.c s390.c s390x.c s390dbf.c ppc64.c x86_64.c \ -- arm.c arm64.c mips.c mips64.c sparc64.c \ -+ arm.c arm64.c mips.c mips64.c sparc64.c loongarch64.c\ - extensions.c remote.c va_server.c va_server_v1.c symbols.c cmdline.c \ - lkcd_common.c lkcd_v1.c lkcd_v2_v3.c lkcd_v5.c lkcd_v7.c lkcd_v8.c\ - lkcd_fix_mem.c s390_dump.c lkcd_x86_trace.c \ -@@ -83,7 +83,7 @@ OBJECT_FILES=main.o tools.o global_data.o memory.o filesys.o help.o task.o \ - build_data.o kernel.o test.o gdb_interface.o net.o dev.o bpf.o \ - printk.o \ - alpha.o x86.o ppc.o ia64.o s390.o s390x.o s390dbf.o ppc64.o x86_64.o \ -- arm.o arm64.o mips.o mips64.o sparc64.o \ -+ arm.o arm64.o mips.o mips64.o sparc64.o loongarch64.o\ - extensions.o remote.o va_server.o va_server_v1.o symbols.o cmdline.o \ - lkcd_common.o lkcd_v1.o lkcd_v2_v3.o lkcd_v5.o lkcd_v7.o lkcd_v8.o \ - lkcd_fix_mem.o s390_dump.o netdump.o diskdump.o makedumpfile.o xendump.o \ -@@ -182,6 +182,9 @@ GDB_7.3.1_OFILES=${GDB}/gdb/symtab.o - GDB_7.6_FILES= - GDB_7.6_OFILES=${GDB}/gdb/symtab.o - -+GDB_8.1_FILES= -+GDB_8.1_OFILES=${GDB}/gdb/symtab.o -+ - # - # GDB_FLAGS is passed up from the gdb Makefile. - # -@@ -272,12 +275,6 @@ gdb_patch: - if [ "${ARCH}" = "x86_64" ] && [ "${TARGET}" = "PPC64" ] && [ -f ${GDB}-ppc64le-support.patch ]; then \ - patch -d ${GDB} -p1 -F0 < ${GDB}-ppc64le-support.patch ; \ - fi -- if [ -f /usr/include/proc_service.h ]; then \ -- grep 'extern ps_err_e ps_get_thread_area (struct' /usr/include/proc_service.h; \ -- if [ $$? -eq 0 ]; then \ -- patch -p0 < ${GDB}-proc_service.h.patch; \ -- fi; \ -- fi - - library: make_build_data ${OBJECT_FILES} - ar -rs ${PROGRAM}lib.a ${OBJECT_FILES} -@@ -449,6 +446,9 @@ mips64.o: ${GENERIC_HFILES} ${REDHAT_HFILES} mips64.c - sparc64.o: ${GENERIC_HFILES} ${REDHAT_HFILES} sparc64.c - ${CC} -c ${CRASH_CFLAGS} sparc64.c ${WARNING_OPTIONS} ${WARNING_ERROR} - -+loongarch64.o: ${GENERIC_HFILES} ${REDHAT_HFILES} loongarch64.c -+ ${CC} -c ${CRASH_CFLAGS} loongarch64.c ${WARNING_OPTIONS} ${WARNING_ERROR} -+ - s390.o: ${GENERIC_HFILES} ${IBM_HFILES} s390.c - ${CC} -c ${CRASH_CFLAGS} s390.c ${WARNING_OPTIONS} ${WARNING_ERROR} - -diff --git a/README b/README -index ef2c08f..e1c5795 100644 ---- a/README -+++ b/README -@@ -37,8 +37,8 @@ - These are the current prerequisites: - - o At this point, x86, ia64, x86_64, ppc64, ppc, arm, arm64, alpha, mips, -- mips64, s390 and s390x-based kernels are supported. Other architectures -- may be addressed in the future. -+ mips64, loongarch64, s390 and s390x-based kernels are supported. Other -+ architectures may be addressed in the future. - - o One size fits all -- the utility can be run on any Linux kernel version - version dating back to 2.2.5-15. A primary design goal is to always -diff --git a/configure.c b/configure.c -index b691a13..e3aa19d 100644 ---- a/configure.c -+++ b/configure.c -@@ -107,6 +107,7 @@ void add_extra_lib(char *); - #undef MIPS - #undef SPARC64 - #undef MIPS64 -+#undef LOONGARCH64 - - #define UNKNOWN 0 - #define X86 1 -@@ -122,6 +123,7 @@ void add_extra_lib(char *); - #define MIPS 11 - #define SPARC64 12 - #define MIPS64 13 -+#define LOONGARCH64 14 - - #define TARGET_X86 "TARGET=X86" - #define TARGET_ALPHA "TARGET=ALPHA" -@@ -136,6 +138,7 @@ void add_extra_lib(char *); - #define TARGET_MIPS "TARGET=MIPS" - #define TARGET_MIPS64 "TARGET=MIPS64" - #define TARGET_SPARC64 "TARGET=SPARC64" -+#define TARGET_LOONGARCH64 "TARGET=LOONGARCH64" - - #define TARGET_CFLAGS_X86 "TARGET_CFLAGS=-D_FILE_OFFSET_BITS=64" - #define TARGET_CFLAGS_ALPHA "TARGET_CFLAGS=" -@@ -158,16 +161,17 @@ void add_extra_lib(char *); - #define TARGET_CFLAGS_MIPS_ON_X86_64 "TARGET_CFLAGS=-m32 -D_FILE_OFFSET_BITS=64" - #define TARGET_CFLAGS_MIPS64 "TARGET_CFLAGS=" - #define TARGET_CFLAGS_SPARC64 "TARGET_CFLAGS=" -+#define TARGET_CFLAGS_LOONGARCH64 "TARGET_CFLAGS=" - - #define GDB_TARGET_DEFAULT "GDB_CONF_FLAGS=" - #define GDB_TARGET_ARM_ON_X86 "GDB_CONF_FLAGS=--target=arm-elf-linux" --#define GDB_TARGET_ARM_ON_X86_64 "GDB_CONF_FLAGS=--target=arm-elf-linux CFLAGS=-m32" --#define GDB_TARGET_X86_ON_X86_64 "GDB_CONF_FLAGS=--target=i686-pc-linux-gnu CFLAGS=-m32" --#define GDB_TARGET_PPC_ON_PPC64 "GDB_CONF_FLAGS=--target=ppc-elf-linux CFLAGS=-m32" -+#define GDB_TARGET_ARM_ON_X86_64 "GDB_CONF_FLAGS=--target=arm-elf-linux CFLAGS=-m32 CXXFLAGS=-m32" -+#define GDB_TARGET_X86_ON_X86_64 "GDB_CONF_FLAGS=--target=i686-pc-linux-gnu CFLAGS=-m32 CXXFLAGS=-m32" -+#define GDB_TARGET_PPC_ON_PPC64 "GDB_CONF_FLAGS=--target=ppc-elf-linux CFLAGS=-m32 CXXFLAGS=-m32" - #define GDB_TARGET_ARM64_ON_X86_64 "GDB_CONF_FLAGS=--target=aarch64-elf-linux" /* TBD */ - #define GDB_TARGET_PPC64_ON_X86_64 "GDB_CONF_FLAGS=--target=powerpc64le-unknown-linux-gnu" - #define GDB_TARGET_MIPS_ON_X86 "GDB_CONF_FLAGS=--target=mipsel-elf-linux" --#define GDB_TARGET_MIPS_ON_X86_64 "GDB_CONF_FLAGS=--target=mipsel-elf-linux CFLAGS=-m32" -+#define GDB_TARGET_MIPS_ON_X86_64 "GDB_CONF_FLAGS=--target=mipsel-elf-linux CFLAGS=-m32 CXXFLAGS=-m32" - - /* - * The original plan was to allow the use of a particular version -@@ -182,9 +186,10 @@ void add_extra_lib(char *); - #define GDB_7_0 (3) - #define GDB_7_3_1 (4) - #define GDB_7_6 (5) --#define SUPPORTED_GDB_VERSIONS (GDB_7_6 + 1) -+#define GDB_8_1 (6) -+#define SUPPORTED_GDB_VERSIONS (GDB_8_1 + 1) - --int default_gdb = GDB_7_6; -+int default_gdb = GDB_8_1; - - struct supported_gdb_version { - char *GDB; -@@ -249,6 +254,15 @@ struct supported_gdb_version { - "GDB_FLAGS=-DGDB_7_6", - "GPLv3" - }, -+ { -+ "GDB=gdb-8.1", -+ "8.1", -+ "GDB_FILES=${GDB_8.1_FILES}", -+ "GDB_OFILES=${GDB_8.1_OFILES}", -+ "GDB_PATCH_FILES=gdb-8.1.patch gdb-8.1-ppc64le-support.patch", -+ "GDB_FLAGS=-DGDB_8_1", -+ "GPLv3" -+ }, - }; - - #define DAEMON 0x1 -@@ -394,6 +408,9 @@ get_current_configuration(struct supported_gdb_version *sp) - #ifdef __sparc_v9__ - target_data.target = SPARC64; - #endif -+#ifdef __loongarch64 -+ target_data.target = LOONGARCH64; -+#endif - - set_initial_target(sp); - -@@ -487,6 +504,10 @@ get_current_configuration(struct supported_gdb_version *sp) - (target_data.target != MIPS64)) - arch_mismatch(sp); - -+ if ((target_data.initial_gdb_target == LOONGARCH64) && -+ (target_data.target != LOONGARCH64)) -+ arch_mismatch(sp); -+ - if ((target_data.initial_gdb_target == X86) && - (target_data.target != X86)) { - if (target_data.target == X86_64) -@@ -650,6 +671,9 @@ show_configuration(void) - case SPARC64: - printf("TARGET: SPARC64\n"); - break; -+ case LOONGARCH64: -+ printf("TARGET: LOONGARCH64\n"); -+ break; - } - - if (strlen(target_data.program)) { -@@ -767,6 +791,10 @@ build_configure(struct supported_gdb_version *sp) - target = TARGET_SPARC64; - target_CFLAGS = TARGET_CFLAGS_SPARC64; - break; -+ case LOONGARCH64: -+ target = TARGET_LOONGARCH64; -+ target_CFLAGS = TARGET_CFLAGS_LOONGARCH64; -+ break; - } - - ldflags = get_extra_flags("LDFLAGS.extra", NULL); -@@ -1364,7 +1392,7 @@ make_spec_file(struct supported_gdb_version *sp) - printf("Vendor: Red Hat, Inc.\n"); - printf("Packager: Dave Anderson \n"); - printf("ExclusiveOS: Linux\n"); -- printf("ExclusiveArch: %%{ix86} alpha ia64 ppc ppc64 ppc64pseries ppc64iseries x86_64 s390 s390x arm aarch64 ppc64le mips mipsel mips64el sparc64\n"); -+ printf("ExclusiveArch: %%{ix86} alpha ia64 ppc ppc64 ppc64pseries ppc64iseries x86_64 s390 s390x arm aarch64 ppc64le mips mipsel mips64el sparc64 loongarch64\n"); - printf("Buildroot: %%{_tmppath}/%%{name}-root\n"); - printf("BuildRequires: ncurses-devel zlib-devel bison\n"); - printf("Requires: binutils\n"); -@@ -1514,6 +1542,12 @@ setup_gdb_defaults(void) - fprintf(stderr, ".gdb configuration: %s\n", sp->GDB_VERSION_IN); - return store_gdb_defaults(sp); - } -+ if (strcmp(buf, "8.1") == 0) { -+ fclose(fp); -+ sp = &supported_gdb_versions[GDB_8_1]; -+ fprintf(stderr, ".gdb configuration: %s\n", sp->GDB_VERSION_IN); -+ return store_gdb_defaults(sp); -+ } - - } - -@@ -1597,6 +1631,8 @@ set_initial_target(struct supported_gdb_version *sp) - target_data.initial_gdb_target = MIPS; - else if (strncmp(buf, "SPARC64", strlen("SPARC64")) == 0) - target_data.initial_gdb_target = SPARC64; -+ else if (strncmp(buf, "LOONGARCH64", strlen("LOONGARCH64")) == 0) -+ target_data.initial_gdb_target = LOONGARCH64; - } - - char * -@@ -1617,6 +1653,7 @@ target_to_name(int target) - case MIPS: return("MIPS"); - case MIPS64: return("MIPS64"); - case SPARC64: return("SPARC64"); -+ case LOONGARCH64: return("LOONGARCH64"); - } - - return "UNKNOWN"; -@@ -1681,6 +1718,10 @@ name_to_target(char *name) - return MIPS64; - else if (strncmp(name, "sparc64", strlen("sparc64")) == 0) - return SPARC64; -+ else if (strncmp(name, "loongarch64", strlen("loongarch64")) == 0) -+ return LOONGARCH64; -+ else if (strncmp(name, "LOONGARCH64", strlen("LOONGARCH64")) == 0) -+ return LOONGARCH64; - - return UNKNOWN; - } -diff --git a/crash_target.c b/crash_target.c -new file mode 100644 -index 0000000..efec05b ---- /dev/null -+++ b/crash_target.c -@@ -0,0 +1,135 @@ -+/* -+ * crash_target.c -+ * -+ * Copyright (c) 2021 VMware, Inc. -+ * -+ * 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 2 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. -+ * -+ * Author: Alexey Makhalov -+ */ -+#include -+#include "top.h" -+#include "target.h" -+#include "inferior.h" -+#include "regcache.h" -+#include "gdbarch.h" -+ -+void crash_target_init (void); -+ -+extern "C" int gdb_readmem_callback(unsigned long, void *, int, int); -+extern "C" int crash_get_nr_cpus(void); -+extern "C" int crash_get_cpu_reg (int cpu, int regno, const char *regname, -+ int regsize, void *val); -+extern struct thread_info *add_thread_silent (ptid_t ptid); -+extern void switch_to_thread (thread_info *thr); -+ -+ -+/* The crash target. */ -+ -+static const target_info crash_target_info = { -+ "crash", -+ N_("Local core dump file"), -+ N_("Use a built-in crash instance as a target.") -+}; -+ -+class crash_target final -+{ -+public: -+ -+ const target_info &info () const -+ { return crash_target_info; } -+ -+ void fetch_registers (struct regcache *, int); -+ enum target_xfer_status xfer_partial (enum target_object object, -+ const char *annex, -+ gdb_byte *readbuf, -+ const gdb_byte *writebuf, -+ ULONGEST offset, ULONGEST len, -+ ULONGEST *xfered_len); -+ -+ bool has_all_memory () { return true; } -+ bool has_memory () { return true; } -+ bool has_stack () { return true; } -+ bool has_registers () { return true; } -+ bool thread_alive (ptid_t ptid) { return true; } -+ std::string pid_to_str (ptid_t ptid) -+ { return string_printf ("CPU %ld", ptid.tid ()); } -+ -+}; -+ -+ -+/* We just get all the registers, so we don't use regno. */ -+void -+crash_target::fetch_registers (struct regcache *regcache, int regno) -+{ -+ gdb_byte regval[16]; -+ int cpu = inferior_ptid.tid(); -+ struct gdbarch *arch = regcache->arch (); -+ -+ for (int r = 0; r < gdbarch_num_regs (arch); r++) -+ { -+ const char *regname = gdbarch_register_name(arch, r); -+ int regsize = register_size (arch, r); -+ if (regsize > sizeof (regval)) -+ error (_("fatal error: buffer size is not enough to fit register value")); -+ -+ if (crash_get_cpu_reg (cpu, r, regname, regsize, (void *)®val)) -+ regcache->raw_supply (r, regval); -+ else -+ regcache->raw_supply (r, NULL); -+ } -+} -+ -+enum target_xfer_status -+crash_target::xfer_partial (enum target_object object, const char *annex, -+ gdb_byte *readbuf, const gdb_byte *writebuf, -+ ULONGEST offset, ULONGEST len, ULONGEST *xfered_len) -+{ -+ if (object != TARGET_OBJECT_MEMORY && object != TARGET_OBJECT_STACK_MEMORY -+ && object != TARGET_OBJECT_CODE_MEMORY) -+ return TARGET_XFER_E_IO; -+ -+ if (gdb_readmem_callback(offset, (void *)(readbuf ? readbuf : writebuf), len, !readbuf)) -+ { -+ *xfered_len = len; -+ return TARGET_XFER_OK; -+ } -+ -+ return TARGET_XFER_E_IO; -+} -+ -+#define CRASH_INFERIOR_PID 1 -+ -+void -+crash_target_init (void) -+{ -+ int nr_cpus = crash_get_nr_cpus(); -+ crash_target *target = new crash_target (); -+ -+ /* Own the target until it is successfully pushed. */ -+// target_ops_up target_holder (target); -+ -+// push_target (std::move (target_holder)); -+ -+ inferior_appeared (current_inferior (), CRASH_INFERIOR_PID); -+ for (int i = 0; i < nr_cpus; i++) -+ { -+ thread_info *thread = add_thread_silent (ptid_t(CRASH_INFERIOR_PID, 0, i)); -+ if (!i) -+ switch_to_thread (thread); -+ } -+ -+ /* Fetch all registers from core file. */ -+ target_fetch_registers (get_current_regcache (), -1); -+ -+ /* Now, set up the frame cache. */ -+ reinit_frame_cache (); -+} -diff --git a/defs.h b/defs.h -index 43eff46..d40b226 100644 ---- a/defs.h -+++ b/defs.h -@@ -75,7 +75,7 @@ - #if !defined(X86) && !defined(X86_64) && !defined(ALPHA) && !defined(PPC) && \ - !defined(IA64) && !defined(PPC64) && !defined(S390) && !defined(S390X) && \ - !defined(ARM) && !defined(ARM64) && !defined(MIPS) && !defined(MIPS64) && \ -- !defined(SPARC64) -+ !defined(SPARC64) && !defined(LOONGARCH64) - #ifdef __alpha__ - #define ALPHA - #endif -@@ -117,6 +117,9 @@ - #ifdef __sparc_v9__ - #define SPARC64 - #endif -+#ifdef __loongarch64 -+#define LOONGARCH64 -+#endif - #endif - - #ifdef X86 -@@ -158,6 +161,9 @@ - #ifdef SPARC64 - #define NR_CPUS (4096) - #endif -+#ifdef LOONGARCH64 -+#define NR_CPUS (256) -+#endif - - #define NR_DEVICE_DUMPS (64) - -@@ -515,7 +521,6 @@ struct program_context { - struct sigaction gdb_sigaction; /* gdb's SIGINT sigaction. */ - jmp_buf main_loop_env; /* longjmp target default */ - jmp_buf foreach_loop_env; /* longjmp target within foreach */ -- jmp_buf gdb_interface_env; /* longjmp target for gdb error catch */ - struct termios termios_orig; /* non-raw settings */ - struct termios termios_raw; /* while gathering command input */ - int ncmds; /* number of commands in menu */ -@@ -1014,6 +1019,7 @@ struct machdep_table { - ulong (*processor_speed)(void); - int (*uvtop)(struct task_context *, ulong, physaddr_t *, int); - int (*kvtop)(struct task_context *, ulong, physaddr_t *, int); -+ int (*get_cpu_reg)(int, int, const char *, int, void *); - ulong (*get_task_pgd)(ulong); - void (*dump_irq)(int); - void (*get_stack_frame)(struct bt_info *, ulong *, ulong *); -@@ -2003,6 +2009,8 @@ struct offset_table { /* stash of commonly-used offsets */ - long atomic_t_counter; - long percpu_counter_count; - long mm_struct_mm_count; -+ long task_struct_thread_reg01; -+ long task_struct_thread_reg03; - long task_struct_thread_reg29; - long task_struct_thread_reg31; - long pt_regs_regs; -@@ -2586,7 +2594,7 @@ struct datatype_member { /* minimal definition of a structure/union */ - long member_size; - int member_typecode; - ulong flags; -- char *tagname; /* tagname and value for enums */ -+ const char *tagname; /* tagname and value for enums */ - long value; - ulong vaddr; - }; -@@ -3434,6 +3442,43 @@ struct arm64_stackframe { - #define _MAX_PHYSMEM_BITS 48 - #endif /* MIPS64 */ - -+#ifdef LOONGARCH64 -+#define _64BIT_ -+#define MACHINE_TYPE "LOONGARCH64" -+ -+#define PAGEBASE(X) (((ulong)(X)) & (ulong)machdep->pagemask) -+ -+#define IS_XKPRANGE(X) (((X) >= 0x8000000000000000lu) && \ -+ ((X) < 0xc000000000000000lu)) -+ -+#define PTOV(X) ((ulong)(X) + 0x9000000000000000lu) -+#define VTOP(X) ((ulong)(X) & 0x0000fffffffffffflu) -+ -+#define IS_VMALLOC_ADDR(X) (vt->vmalloc_start && (ulong)(X) >= vt->vmalloc_start) -+ -+#define DEFAULT_MODULES_VADDR 0xffff800000000000lu -+#define MODULES_VADDR (machdep->machspec->modules_vaddr) -+#define MODULES_END (machdep->machspec->modules_end) -+#define VMALLOC_START (machdep->machspec->vmalloc_start_addr) -+#define VMALLOC_END (machdep->machspec->vmalloc_end) -+ -+#define __SWP_TYPE_SHIFT 16 -+#define __SWP_TYPE_BITS 8 -+#define __SWP_TYPE_MASK ((1 << __SWP_TYPE_BITS) - 1) -+#define __SWP_OFFSET_SHIFT (__SWP_TYPE_BITS + __SWP_TYPE_SHIFT) -+ -+#define SWP_TYPE(entry) (((entry) >> __SWP_TYPE_SHIFT) & __SWP_TYPE_MASK) -+#define SWP_OFFSET(entry) ((entry) >> __SWP_OFFSET_SHIFT) -+ -+#define __swp_type(entry) SWP_TYPE(entry) -+#define __swp_offset(entry) SWP_OFFSET(entry) -+ -+#define TIF_SIGPENDING (1) -+ -+#define _SECTION_SIZE_BITS 28 -+#define _MAX_PHYSMEM_BITS 48 -+#endif /* LOONGARCH64 */ -+ - #ifdef X86 - #define _32BIT_ - #define MACHINE_TYPE "X86" -@@ -4482,6 +4527,10 @@ struct machine_specific { - #define MAX_HEXADDR_STRLEN (16) - #define UVADDR_PRLEN (16) - #endif -+#ifdef LOONGARCH64 -+#define MAX_HEXADDR_STRLEN (16) -+#define UVADDR_PRLEN (16) -+#endif - - #define BADADDR ((ulong)(-1)) - #define BADVAL ((ulong)(-1)) -@@ -4726,7 +4775,7 @@ struct gnu_request { - long member_length; - int member_typecode; - long value; -- char *tagname; -+ const char *tagname; - ulong pc; - ulong sp; - ulong ra; -@@ -4738,13 +4787,10 @@ struct gnu_request { - ulong task; - ulong debug; - struct stack_hook *hookp; -- struct global_iterator { -- int finished; -- int block_index; -- struct symtab *symtab; -- struct symbol *sym; -- struct objfile *obj; -- } global_iterator; -+ ulong lowest; -+ ulong highest; -+ void (*callback) (struct gnu_request *req, void *data); -+ void *callback_data; - struct load_module *lm; - char *member_main_type_name; - char *member_main_type_tag_name; -@@ -4774,7 +4820,7 @@ struct gnu_request { - #define GNU_USER_PRINT_OPTION (16) - #define GNU_SET_CRASH_BLOCK (17) - #define GNU_GET_FUNCTION_RANGE (18) --#define GNU_GET_NEXT_DATATYPE (19) -+#define GNU_ITERATE_DATATYPES (19) - #define GNU_LOOKUP_STRUCT_CONTENTS (20) - #define GNU_DEBUG_COMMAND (100) - /* -@@ -4799,14 +4845,15 @@ struct gnu_request { - /* - * function prototypes required by modified gdb source files. - */ --int console(char *, ...); --int gdb_CRASHDEBUG(ulong); -+extern "C" int console(const char *, ...); -+extern "C" int gdb_CRASHDEBUG(ulong); - int gdb_readmem_callback(ulong, void *, int, int); - void patch_load_module(struct objfile *objfile, struct minimal_symbol *msymbol); --int patch_kernel_symbol(struct gnu_request *); -+extern "C" int patch_kernel_symbol(struct gnu_request *); - struct syment *symbol_search(char *); - int gdb_line_number_callback(ulong, ulong, ulong); - int gdb_print_callback(ulong); -+extern "C" int same_file(char *, char *); - #endif - - #ifndef GDB_COMMON -@@ -4820,8 +4867,8 @@ enum type_code { - TYPE_CODE_STRUCT, /* C struct or Pascal record */ - TYPE_CODE_UNION, /* C union or Pascal variant part */ - TYPE_CODE_ENUM, /* Enumeration type */ --#if defined(GDB_5_3) || defined(GDB_6_0) || defined(GDB_6_1) || defined(GDB_7_0) || defined(GDB_7_3_1) || defined(GDB_7_6) --#if defined(GDB_7_0) || defined(GDB_7_3_1) || defined(GDB_7_6) -+#if defined(GDB_5_3) || defined(GDB_6_0) || defined(GDB_6_1) || defined(GDB_7_0) || defined(GDB_7_3_1) || defined(GDB_7_6) || defined(GDB_8_1) -+#if defined(GDB_7_0) || defined(GDB_7_3_1) || defined(GDB_7_6) || defined(GDB_8_1) - TYPE_CODE_FLAGS, /* Bit flags type */ - #endif - TYPE_CODE_FUNC, /* Function type */ -@@ -5060,6 +5107,9 @@ void dump_build_data(void); - #ifdef SPARC64 - #define machdep_init(X) sparc64_init(X) - #endif -+#ifdef LOONGARCH64 -+#define machdep_init(X) loongarch64_init(X) -+#endif - int clean_exit(int); - int untrusted_file(FILE *, char *); - char *readmem_function_name(void); -@@ -5098,7 +5148,7 @@ void exec_args_input_file(struct command_table_entry *, struct args_input_file * - FILE *set_error(char *); - int __error(int, char *, ...); - #define error __error /* avoid conflict with gdb error() */ --int console(char *, ...); -+int console(const char *, ...); - void create_console_device(char *); - int console_off(void); - int console_on(int); -@@ -5488,9 +5538,7 @@ int file_dump(ulong, ulong, ulong, int, int); - #define DUMP_DENTRY_ONLY 0x4 - #define DUMP_EMPTY_FILE 0x8 - #define DUMP_FILE_NRPAGES 0x10 --#endif /* !GDB_COMMON */ - int same_file(char *, char *); --#ifndef GDB_COMMON - int cleanup_memory_driver(void); - - -@@ -5543,6 +5591,9 @@ void display_help_screen(char *); - #ifdef SPARC64 - #define dump_machdep_table(X) sparc64_dump_machdep_table(X) - #endif -+#ifdef LOONGARCH64 -+#define dump_machdep_table(X) loongarch64_dump_machdep_table(X) -+#endif - extern char *help_pointer[]; - extern char *help_alias[]; - extern char *help_ascii[]; -@@ -6580,6 +6631,109 @@ int sparc64_vmalloc_addr(ulong); - error(FATAL, "The -d option is not applicable to sparc64.\n") - #endif - -+/* -+ * loongarch64.c -+ */ -+void loongarch64_display_regs_from_elf_notes(int, FILE *); -+ -+#ifdef LOONGARCH64 -+void loongarch64_init(int); -+void loongarch64_dump_machdep_table(ulong); -+ -+#define display_idt_table() \ -+ error(FATAL, "-d option is not applicable to LOONGARCH64 architecture\n") -+ -+/* from arch/loongarch/include/asm/ptrace.h */ -+struct loongarch64_pt_regs { -+ /* Saved main processor registers. */ -+ unsigned long regs[32]; -+ -+ /* Saved special registers. */ -+ unsigned long csr_crmd; -+ unsigned long csr_prmd; -+ unsigned long csr_euen; -+ unsigned long csr_ecfg; -+ unsigned long csr_estat; -+ unsigned long csr_epc; -+ unsigned long csr_badvaddr; -+ unsigned long orig_a0; -+}; -+ -+struct loongarch64_unwind_frame { -+ unsigned long sp; -+ unsigned long pc; -+ unsigned long ra; -+}; -+ -+#define KSYMS_START (0x1) -+ -+struct machine_specific { -+ ulong phys_base; -+ ulong vmalloc_start_addr; -+ ulong modules_vaddr; -+ ulong modules_end; -+ -+ struct loongarch64_pt_regs *crash_task_regs; -+}; -+ -+/* -+ * Basic page table format: -+ * -+ * 63 62 61 PALEN-1 12 10 9 8 7 6 5 4 3 2 1 0 -+ * +----+--+--+------+--------------------+----+--+--+-+-+-+---+---+-+-+ -+ * |RPLV|NX|NR| | PA[PALEN-1:12] | |SP|PN|W|P|G|MAT|PLV|D|V| -+ * +----+--+--+------+--------------------+----+--+--+-+-+-+---+---+-+-+ -+ * -+ * -+ * Huge page table format: -+ * -+ * 63 62 61 PALEN-1 12 10 9 8 7 6 5 4 3 2 1 0 -+ * +----+--+--+------+-----------------+--+----+--+--+-+-+-+---+---+-+-+ -+ * |RPLV|NX|NR| | PA[PALEN-1:12] | G| |SP|PN|W|P|H|MAT|PLV|D|V| -+ * +----+--+--+------+-----------------+--+----+--+--+-+-+-+---+---+-+-+ -+ * -+ */ -+/* from arch/loongarch/include/asm/pgtable-bits.h */ -+ -+/* Page table bits */ -+#define _PAGE_VALID_SHIFT 0 -+#define _PAGE_DIRTY_SHIFT 1 -+#define _PAGE_PLV_SHIFT 2 /* 2~3, two bits */ -+#define _CACHE_SHIFT 4 /* 4~5, two bits */ -+#define _PAGE_GLOBAL_SHIFT 6 -+#define _PAGE_HUGE_SHIFT 6 /* HUGE is a PMD bit */ -+#define _PAGE_PRESENT_SHIFT 7 -+#define _PAGE_WRITE_SHIFT 8 -+#define _PAGE_PROTNONE_SHIFT 9 -+#define _PAGE_SPECIAL_SHIFT 10 -+#define _PAGE_HGLOBAL_SHIFT 12 /* HGlobal is a PMD bit */ -+#define _PAGE_PFN_SHIFT 12 -+#define _PAGE_PFN_END_SHIFT 48 -+#define _PAGE_NO_READ_SHIFT 61 -+#define _PAGE_NO_EXEC_SHIFT 62 -+#define _PAGE_RPLV_SHIFT 63 -+ -+/* Used only by software */ -+#define _PAGE_PRESENT (1UL << _PAGE_PRESENT_SHIFT) -+#define _PAGE_WRITE (1UL << _PAGE_WRITE_SHIFT) -+#define _PAGE_PROTNONE (1UL << _PAGE_PROTNONE_SHIFT) -+#define _PAGE_SPECIAL (1UL << _PAGE_SPECIAL_SHIFT) -+ -+/* Used by TLB hardware (placed in EntryLo*) */ -+#define _PAGE_VALID (1UL << _PAGE_VALID_SHIFT) -+#define _PAGE_DIRTY (1UL << _PAGE_DIRTY_SHIFT) -+#define _PAGE_PLV (3UL << _PAGE_PLV_SHIFT) -+#define _PAGE_GLOBAL (1UL << _PAGE_GLOBAL_SHIFT) -+#define _PAGE_HUGE (1UL << _PAGE_HUGE_SHIFT) -+#define _PAGE_HGLOBAL (1UL << _PAGE_HGLOBAL_SHIFT) -+#define _PAGE_NO_READ (1UL << _PAGE_NO_READ_SHIFT) -+#define _PAGE_NO_EXEC (1UL << _PAGE_NO_EXEC_SHIFT) -+#define _PAGE_RPLV (1UL << _PAGE_RPLV_SHIFT) -+#define _CACHE_MASK (3UL << _CACHE_SHIFT) -+#define _PFN_SHIFT (PAGESHIFT() - 12 + _PAGE_PFN_SHIFT) -+ -+#endif /* LOONGARCH64 */ -+ - /* - * netdump.c - */ -@@ -6862,6 +7016,7 @@ int vmware_vmss_get_nr_cpus(void); - int vmware_vmss_get_cr3_cr4_idtr(int, ulong *, ulong *, ulong *); - int vmware_vmss_phys_base(ulong *phys_base); - int vmware_vmss_set_phys_base(ulong); -+int vmware_vmss_get_cpu_reg(int, int, const char *, int, void *); - - /* - * vmware_guestdump.c -@@ -7181,10 +7336,10 @@ void gdb_readnow_warning(void); - int gdb_set_crash_scope(ulong, char *); - extern int *gdb_output_format; - extern unsigned int *gdb_print_max; --extern int *gdb_prettyprint_structs; --extern int *gdb_prettyprint_arrays; --extern int *gdb_repeat_count_threshold; --extern int *gdb_stop_print_at_null; -+extern unsigned char *gdb_prettyprint_structs; -+extern unsigned char *gdb_prettyprint_arrays; -+extern unsigned int *gdb_repeat_count_threshold; -+extern unsigned char *gdb_stop_print_at_null; - extern unsigned int *gdb_output_radix; - - /* -@@ -7286,4 +7441,53 @@ extern int have_full_symbols(void); - #define XEN_HYPERVISOR_ARCH - #endif - -+/* -+ * Register numbers must be in sync with gdb/features/i386/64bit-core.c -+ * to make crash_target->fetch_registers() ---> machdep->get_cpu_reg() -+ * working properly. -+ */ -+enum x86_64_regnum { -+ RAX_REGNUM, -+ RBX_REGNUM, -+ RCX_REGNUM, -+ RDX_REGNUM, -+ RSI_REGNUM, -+ RDI_REGNUM, -+ RBP_REGNUM, -+ RSP_REGNUM, -+ R8_REGNUM, -+ R9_REGNUM, -+ R10_REGNUM, -+ R11_REGNUM, -+ R12_REGNUM, -+ R13_REGNUM, -+ R14_REGNUM, -+ R15_REGNUM, -+ RIP_REGNUM, -+ EFLAGS_REGNUM, -+ CS_REGNUM, -+ SS_REGNUM, -+ DS_REGNUM, -+ ES_REGNUM, -+ FS_REGNUM, -+ GS_REGNUM, -+ ST0_REGNUM, -+ ST1_REGNUM, -+ ST2_REGNUM, -+ ST3_REGNUM, -+ ST4_REGNUM, -+ ST5_REGNUM, -+ ST6_REGNUM, -+ ST7_REGNUM, -+ FCTRL_REGNUM, -+ FSTAT_REGNUM, -+ FTAG_REGNUM, -+ FISEG_REGNUM, -+ FIOFF_REGNUM, -+ FOSEG_REGNUM, -+ FOOFF_REGNUM, -+ FOP_REGNUM, -+ LAST_REGNUM -+}; -+ - #endif /* !GDB_COMMON */ -diff --git a/diskdump.c b/diskdump.c -index 112f769..f4f6ff4 100644 ---- a/diskdump.c -+++ b/diskdump.c -@@ -625,6 +625,9 @@ restart: - else if (STRNEQ(header->utsname.machine, "aarch64") && - machine_type_mismatch(file, "ARM64", NULL, 0)) - goto err; -+ else if (STRNEQ(header->utsname.machine, "loongarch64") && -+ machine_type_mismatch(file, "LOONGARCH64", NULL, 0)) -+ goto err; - - if (header->block_size != block_size) { - block_size = header->block_size; -@@ -794,6 +797,8 @@ restart: - dd->machine_type = EM_AARCH64; - else if (machine_type("SPARC64")) - dd->machine_type = EM_SPARCV9; -+ else if (machine_type("LOONGARCH64")) -+ dd->machine_type = EM_LOONGARCH; - else { - error(INFO, "%s: unsupported machine type: %s\n", - DISKDUMP_VALID() ? "diskdump" : "compressed kdump", -@@ -1531,6 +1536,12 @@ get_diskdump_regs_mips(struct bt_info *bt, ulong *eip, ulong *esp) - machdep->get_stack_frame(bt, eip, esp); - } - -+static void -+get_diskdump_regs_loongarch64(struct bt_info *bt, ulong *eip, ulong *esp) -+{ -+ machdep->get_stack_frame(bt, eip, esp); -+} -+ - static void - get_diskdump_regs_sparc64(struct bt_info *bt, ulong *eip, ulong *esp) - { -@@ -1610,6 +1621,10 @@ get_diskdump_regs(struct bt_info *bt, ulong *eip, ulong *esp) - get_diskdump_regs_sparc64(bt, eip, esp); - break; - -+ case EM_LOONGARCH: -+ get_diskdump_regs_loongarch64(bt, eip, esp); -+ break; -+ - default: - error(FATAL, "%s: unsupported machine type: %s\n", - DISKDUMP_VALID() ? "diskdump" : "compressed kdump", -@@ -1756,7 +1771,8 @@ dump_note_offsets(FILE *fp) - qemu = FALSE; - if (machine_type("X86_64") || machine_type("S390X") || - machine_type("ARM64") || machine_type("PPC64") || -- machine_type("SPARC64") || machine_type("MIPS64")) { -+ machine_type("SPARC64") || machine_type("MIPS64") || -+ machine_type("LOONGARCH64")) { - note64 = (void *)dd->notes_buf + tot; - len = sizeof(Elf64_Nhdr); - if (STRNEQ((char *)note64 + len, "QEMU")) -@@ -1867,6 +1883,8 @@ __diskdump_memory_dump(FILE *fp) - fprintf(fp, "(EM_AARCH64)\n"); break; - case EM_SPARCV9: - fprintf(fp, "(EM_SPARCV9)\n"); break; -+ case EM_LOONGARCH: -+ fprintf(fp, "(EM_LOONGARCH)\n"); break; - default: - fprintf(fp, "(unknown)\n"); break; - } -@@ -2553,6 +2571,9 @@ diskdump_display_regs(int cpu, FILE *ofp) - - if (machine_type("MIPS64")) - mips64_display_regs_from_elf_notes(cpu, ofp); -+ -+ if (machine_type("LOONGARCH64")) -+ loongarch64_display_regs_from_elf_notes(cpu, ofp); - } - - void -@@ -2563,7 +2584,8 @@ dump_registers_for_compressed_kdump(void) - if (!KDUMP_CMPRS_VALID() || (dd->header->header_version < 4) || - !(machine_type("X86") || machine_type("X86_64") || - machine_type("ARM64") || machine_type("PPC64") || -- machine_type("MIPS") || machine_type("MIPS64"))) -+ machine_type("MIPS") || machine_type("MIPS64") || -+ machine_type("LOONGARCH64"))) - error(FATAL, "-r option not supported for this dumpfile\n"); - - if (machine_type("ARM64") && (kt->cpus != dd->num_prstatus_notes)) -@@ -2593,13 +2615,22 @@ diskdump_kaslr_check() - return FALSE; - } - --#ifdef X86_64 - int - diskdump_get_nr_cpus(void) - { -- return dd->num_qemu_notes; -+ if (dd->num_prstatus_notes) -+ return dd->num_prstatus_notes; -+ else if (dd->num_qemu_notes) -+ return dd->num_qemu_notes; -+ else if (dd->num_vmcoredd_notes) -+ return dd->num_vmcoredd_notes; -+ else if (dd->header->nr_cpus) -+ return dd->header->nr_cpus; -+ -+ return 1; - } - -+#ifdef X86_64 - QEMUCPUState * - diskdump_get_qemucpustate(int cpu) - { -diff --git a/gdb-7.6-proc_service.h.patch b/gdb-7.6-proc_service.h.patch -deleted file mode 100644 -index e4a788e..0000000 ---- a/gdb-7.6-proc_service.h.patch -+++ /dev/null -@@ -1,67 +0,0 @@ ----- gdb-7.6/gdb/gdb_proc_service.h.orig --+++ gdb-7.6/gdb/gdb_proc_service.h --@@ -115,7 +115,7 @@ extern pid_t ps_getpid (struct ps_procha -- /* Fetch the special per-thread address associated with the given LWP. -- This call is only used on a few platforms (most use a normal register). -- The meaning of the `int' parameter is machine-dependent. */ ---extern ps_err_e ps_get_thread_area (const struct ps_prochandle *, --+extern ps_err_e ps_get_thread_area (struct ps_prochandle *, -- lwpid_t, int, psaddr_t *); -- -- ----- gdb-7.6/gdb/amd64-linux-nat.c.orig --+++ gdb-7.6/gdb/amd64-linux-nat.c --@@ -493,7 +493,7 @@ amd64_linux_new_fork (struct lwp_info *p -- a request for a thread's local storage address. */ -- -- ps_err_e ---ps_get_thread_area (const struct ps_prochandle *ph, --+ps_get_thread_area (struct ps_prochandle *ph, -- lwpid_t lwpid, int idx, void **base) -- { -- if (gdbarch_bfd_arch_info (target_gdbarch ())->bits_per_word == 32) ----- gdb-7.6/gdb/aarch64-linux-nat.c.orig --+++ gdb-7.6/gdb/aarch64-linux-nat.c --@@ -750,7 +750,7 @@ aarch64_linux_new_fork (struct lwp_info -- storage (or its descriptor). */ -- -- ps_err_e ---ps_get_thread_area (const struct ps_prochandle *ph, --+ps_get_thread_area (struct ps_prochandle *ph, -- lwpid_t lwpid, int idx, void **base) -- { -- struct iovec iovec; ----- gdb-7.6/gdb/arm-linux-nat.c.orig --+++ gdb-7.6/gdb/arm-linux-nat.c --@@ -613,7 +613,7 @@ supply_fpregset (struct regcache *regcac -- /* Fetch the thread-local storage pointer for libthread_db. */ -- -- ps_err_e ---ps_get_thread_area (const struct ps_prochandle *ph, --+ps_get_thread_area (struct ps_prochandle *ph, -- lwpid_t lwpid, int idx, void **base) -- { -- if (ptrace (PTRACE_GET_THREAD_AREA, lwpid, NULL, base) != 0) ----- gdb-7.6/gdb/i386-linux-nat.c.orig --+++ gdb-7.6/gdb/i386-linux-nat.c --@@ -849,7 +849,7 @@ i386_linux_new_fork (struct lwp_info *pa -- storage (or its descriptor). */ -- -- ps_err_e ---ps_get_thread_area (const struct ps_prochandle *ph, --+ps_get_thread_area (struct ps_prochandle *ph, -- lwpid_t lwpid, int idx, void **base) -- { -- /* NOTE: cagney/2003-08-26: The definition of this buffer is found ----- gdb-7.6/gdb/mips-linux-nat.c.orig --+++ gdb-7.6/gdb/mips-linux-nat.c --@@ -154,7 +154,7 @@ mips64_linux_register_addr (struct gdbarch *gdbarch, int regno, int store) -- /* Fetch the thread-local storage pointer for libthread_db. */ -- -- ps_err_e ---ps_get_thread_area (const struct ps_prochandle *ph, --+ps_get_thread_area (struct ps_prochandle *ph, -- lwpid_t lwpid, int idx, void **base) -- { -- if (ptrace (PTRACE_GET_THREAD_AREA, lwpid, NULL, base) != 0) -- -diff --git a/gdb-7.6.patch b/gdb-7.6.patch -deleted file mode 100644 -index 106d164..0000000 ---- a/gdb-7.6.patch -+++ /dev/null -@@ -1,2558 +0,0 @@ -- --# When this file is updated in an existing source tree, it gets re-applied --# during the next build using "patch -N --fuzz=0", which ignores patches --# that have already been applied. However, if a gdb file has been modified --# multiple times, the subsequent patching may fail to recognize that a --# given patch has been previously applied, and will attempt to re-apply it. --# To prevent any uninintended consequences, this file also acts as a --# shell script that can restore any gdb file to its original state prior --# to all subsequent patch applications. -- --# The gdb-7.6-ppc64le-support.patch will have modified both files below --# during the initial build, so continue previous behavior. -- --if [ "$1" = "PPC64" ] --then -- exit 0 --fi -- --tar xvzmf gdb-7.6.tar.gz \ -- gdb-7.6/gdb/symtab.c \ -- gdb-7.6/gdb/printcmd.c -- --exit 0 -- ----- gdb-7.6/libiberty/Makefile.in.orig --+++ gdb-7.6/libiberty/Makefile.in --@@ -175,6 +175,7 @@ REQUIRED_OFILES = \ -- ./getruntime.$(objext) ./hashtab.$(objext) ./hex.$(objext) \ -- ./lbasename.$(objext) ./lrealpath.$(objext) \ -- ./make-relative-prefix.$(objext) ./make-temp-file.$(objext) \ --+ ./mkstemps.$(objext) \ -- ./objalloc.$(objext) \ -- ./obstack.$(objext) \ -- ./partition.$(objext) ./pexecute.$(objext) ./physmem.$(objext) \ --@@ -206,7 +207,7 @@ CONFIGURED_OFILES = ./asprintf.$(objext) -- ./index.$(objext) ./insque.$(objext) \ -- ./memchr.$(objext) ./memcmp.$(objext) ./memcpy.$(objext) \ -- ./memmem.$(objext) ./memmove.$(objext) \ --- ./mempcpy.$(objext) ./memset.$(objext) ./mkstemps.$(objext) \ --+ ./mempcpy.$(objext) ./memset.$(objext) \ -- ./pex-djgpp.$(objext) ./pex-msdos.$(objext) \ -- ./pex-unix.$(objext) ./pex-win32.$(objext) \ -- ./putenv.$(objext) \ ----- gdb-7.6/opcodes/i386-dis.c.orig --+++ gdb-7.6/opcodes/i386-dis.c --@@ -11510,6 +11510,10 @@ print_insn (bfd_vma pc, disassemble_info -- threebyte = *++codep; -- dp = &dis386_twobyte[threebyte]; -- need_modrm = twobyte_has_modrm[*codep]; --+ if (dp->name && ((strcmp(dp->name, "ud2a") == 0) || (strcmp(dp->name, "ud2") == 0))) { --+ extern int kernel_BUG_encoding_bytes(void); --+ codep += kernel_BUG_encoding_bytes(); --+ } -- codep++; -- } -- else ----- gdb-7.6/gdb/dwarf2read.c.orig --+++ gdb-7.6/gdb/dwarf2read.c --@@ -2670,7 +2670,11 @@ read_index_from_section (struct objfile -- indices. */ -- if (version < 4) -- { --+#ifdef CRASH_MERGE --+ static int warning_printed = 1; --+#else -- static int warning_printed = 0; --+#endif -- if (!warning_printed) -- { -- warning (_("Skipping obsolete .gdb_index section in %s."), --@@ -2689,7 +2693,11 @@ read_index_from_section (struct objfile -- "set use-deprecated-index-sections on". */ -- if (version < 6 && !deprecated_ok) -- { --+#ifdef CRASH_MERGE --+ static int warning_printed = 1; --+#else -- static int warning_printed = 0; --+#endif -- if (!warning_printed) -- { -- warning (_("\ ----- gdb-7.6/gdb/amd64-linux-nat.c.orig --+++ gdb-7.6/gdb/amd64-linux-nat.c --@@ -45,6 +45,17 @@ -- /* ezannoni-2003-07-09: I think this is fixed. The extraneous defs have -- been removed from ptrace.h in the kernel. However, better safe than -- sorry. */ --+#ifdef CRASH_MERGE --+/* --+ * When compiling within a 2.6.25-based Fedora build environment with --+ * gcc 4.3, four new "typedef unsigned int u32;" declarations were --+ * required due to a new ptrace_bts_config structure declaration in --+ * "asm-x86/ptrace-abi.h" that used u32 members, but u32 is defined in --+ * "asm-x86/types.h" within a __KERNEL__ section. They've been changed --+ * to __u32, but this patch remains for building in that environment. --+ */ --+typedef unsigned int u32; --+#endif -- #include -- #include -- #include "gdb_proc_service.h" ----- gdb-7.6/gdb/symfile.c.orig --+++ gdb-7.6/gdb/symfile.c --@@ -693,7 +693,26 @@ default_symfile_offsets (struct objfile -- for (cur_sec = abfd->sections; cur_sec != NULL; cur_sec = cur_sec->next) -- /* We do not expect this to happen; just skip this step if the -- relocatable file has a section with an assigned VMA. */ --- if (bfd_section_vma (abfd, cur_sec) != 0) --+ if (bfd_section_vma (abfd, cur_sec) != 0 --+ /* --+ * Kernel modules may have some non-zero VMAs, i.e., like the --+ * __ksymtab and __ksymtab_gpl sections in this example: --+ * --+ * Section Headers: --+ * [Nr] Name Type Address Offset --+ * Size EntSize Flags Link Info Align --+ * ... --+ * [ 8] __ksymtab PROGBITS 0000000000000060 0000ad90 --+ * 0000000000000010 0000000000000000 A 0 0 16 --+ * [ 9] .rela__ksymtab RELA 0000000000000000 0000ada0 --+ * 0000000000000030 0000000000000018 43 8 8 --+ * [10] __ksymtab_gpl PROGBITS 0000000000000070 0000add0 --+ * 00000000000001a0 0000000000000000 A 0 0 16 --+ * ... --+ * --+ * but they should be treated as if they are NULL. --+ */ --+ && strncmp (bfd_get_section_name (abfd, cur_sec), "__k", 3) != 0) -- break; -- -- if (cur_sec == NULL) --@@ -1122,6 +1141,12 @@ symbol_file_add_with_addrs_or_offsets (b -- error (_("Not confirmed.")); -- -- objfile = allocate_objfile (abfd, flags | (mainline ? OBJF_MAINLINE : 0)); --+#ifdef CRASH_MERGE --+ if (add_flags & SYMFILE_MAINLINE) { --+ extern struct objfile *gdb_kernel_objfile; --+ gdb_kernel_objfile = objfile; --+ } --+#endif -- -- if (parent) -- add_separate_debug_objfile (objfile, parent); --@@ -1484,6 +1509,9 @@ find_separate_debug_file (const char *di -- VEC (char_ptr) *debugdir_vec; -- struct cleanup *back_to; -- int ix; --+#ifdef CRASH_MERGE --+ extern int check_specified_module_tree(char *, char *); --+#endif -- -- /* Set I to max (strlen (canon_dir), strlen (dir)). */ -- i = strlen (dir); --@@ -1513,6 +1541,15 @@ find_separate_debug_file (const char *di -- if (separate_debug_file_exists (debugfile, crc32, objfile)) -- return debugfile; -- --+#ifdef CRASH_MERGE --+{ --+ if (check_specified_module_tree(objfile->name, debugfile) && --+ separate_debug_file_exists(debugfile, crc32, objfile)) { --+ return debugfile; --+ } --+} --+#endif --+ -- /* Then try in the global debugfile directories. -- -- Keep backward compatibility so that DEBUG_FILE_DIRECTORY being "" will --@@ -1583,6 +1620,10 @@ find_separate_debug_file_by_debuglink (s -- char *debugfile; -- unsigned long crc32; -- struct cleanup *cleanups; --+#ifdef CRASH_MERGE --+ char *name_copy; --+ extern char *check_specified_kernel_debug_file(); --+#endif -- -- debuglink = get_debug_link_info (objfile, &crc32); -- --@@ -1635,6 +1676,12 @@ find_separate_debug_file_by_debuglink (s -- } -- -- do_cleanups (cleanups); --+#ifdef CRASH_MERGE --+ if (debugfile == NULL) { --+ name_copy = check_specified_kernel_debug_file(); --+ return (name_copy ? xstrdup(name_copy) : NULL); --+ } --+#endif -- return debugfile; -- } -- --@@ -2409,8 +2456,10 @@ add_symbol_file_command (char *args, int -- so we can't determine what section names are valid. */ -- } -- --+#ifndef CRASH_MERGE -- if (from_tty && (!query ("%s", ""))) -- error (_("Not confirmed.")); --+#endif -- -- symbol_file_add (filename, from_tty ? SYMFILE_VERBOSE : 0, -- section_addrs, flags); --@@ -3690,6 +3739,15 @@ bfd_byte * -- symfile_relocate_debug_section (struct objfile *objfile, -- asection *sectp, bfd_byte *buf) -- { --+#ifdef CRASH_MERGE --+ /* Executable files have all the relocations already resolved. --+ * Handle files linked with --emit-relocs. --+ * http://sources.redhat.com/ml/gdb/2006-08/msg00137.html --+ */ --+ bfd *abfd = objfile->obfd; --+ if ((abfd->flags & EXEC_P) != 0) --+ return NULL; --+#endif -- gdb_assert (objfile->sf->sym_relocate); -- -- return (*objfile->sf->sym_relocate) (objfile, sectp, buf); ----- gdb-7.6/gdb/cli/cli-cmds.c.orig --+++ gdb-7.6/gdb/cli/cli-cmds.c --@@ -466,6 +466,10 @@ show_script_ext_mode (struct ui_file *fi -- If SEARCH_PATH is non-zero, and the file isn't found in cwd, -- search for it in the source search path. */ -- --+#ifdef CRASH_MERGE --+static int crash_from_tty = 0; --+#endif --+ -- int -- find_and_open_script (const char *script_file, int search_path, -- FILE **streamp, char **full_pathp) --@@ -508,6 +512,32 @@ find_and_open_script (const char *script -- return 0; -- } -- --+#ifdef CRASH_MERGE --+ /* --+ * Only allow trusted versions of .gdbinit files to be --+ * sourced during session initialization. --+ */ --+ if (crash_from_tty == -1) --+ { --+ struct stat statbuf; --+ FILE *stream = *streamp; --+ int fd = fileno (stream); --+ if (fstat (fd, &statbuf) < 0) --+ { --+ perror_with_name (*full_pathp); --+ fclose (stream); --+ return 0; --+ } --+ if (statbuf.st_uid != getuid () || (statbuf.st_mode & S_IWOTH)) --+ { --+ extern void untrusted_file(FILE *, char *); --+ untrusted_file(NULL, *full_pathp); --+ fclose (stream); --+ return 0; --+ } --+ } --+#endif --+ -- return 1; -- } -- --@@ -566,7 +596,11 @@ source_script_with_search (const char *f -- If the source command was invoked interactively, throw an -- error. Otherwise (e.g. if it was invoked by a script), -- silently ignore the error. */ --+#ifdef CRASH_MERGE --+ if (from_tty > 0) --+#else -- if (from_tty) --+#endif -- perror_with_name (file); -- else -- return; --@@ -589,7 +623,14 @@ source_script_with_search (const char *f -- void -- source_script (char *file, int from_tty) -- { --+#ifdef CRASH_MERGE --+ crash_from_tty = from_tty; --+#endif -- source_script_with_search (file, from_tty, 0); --+#ifdef CRASH_MERGE --+ crash_from_tty = 0; --+#endif --+ -- } -- -- /* Return the source_verbose global variable to its previous state ----- gdb-7.6/gdb/psymtab.c.orig --+++ gdb-7.6/gdb/psymtab.c --@@ -305,10 +305,14 @@ find_pc_sect_psymtab (struct objfile *ob -- struct minimal_symbol *msymbol) -- { -- struct partial_symtab *pst; --+#ifdef CRASH_MERGE --+ extern int gdb_line_number_callback(unsigned long, unsigned long, unsigned long); --+#endif -- -- /* Try just the PSYMTABS_ADDRMAP mapping first as it has better granularity -- than the later used TEXTLOW/TEXTHIGH one. */ -- --+#ifndef __i386__ -- if (objfile->psymtabs_addrmap != NULL) -- { -- pst = addrmap_find (objfile->psymtabs_addrmap, pc); --@@ -343,6 +347,7 @@ find_pc_sect_psymtab (struct objfile *ob -- } -- -- next: --+#endif -- -- /* Existing PSYMTABS_ADDRMAP mapping is present even for PARTIAL_SYMTABs -- which still have no corresponding full SYMTABs read. But it is not --@@ -361,7 +366,12 @@ find_pc_sect_psymtab (struct objfile *ob -- -- best_pst = find_pc_sect_psymtab_closer (objfile, pc, section, pst, -- msymbol); --+#ifdef CRASH_MERGE --+ if ((best_pst != NULL) && --+ gdb_line_number_callback(pc, pst->textlow, pst->texthigh)) --+#else -- if (best_pst != NULL) --+#endif -- return best_pst; -- } -- ----- gdb-7.6/gdb/symtab.c.orig --+++ gdb-7.6/gdb/symtab.c --@@ -1198,7 +1198,9 @@ demangle_for_lookup (const char *name, e -- doesn't affect these calls since they are looking for a known -- variable and thus can probably assume it will never hit the C++ -- code). */ --- --+#ifdef CRASH_MERGE --+static void gdb_bait_and_switch(char *, struct symbol *); --+#endif -- struct symbol * -- lookup_symbol_in_language (const char *name, const struct block *block, -- const domain_enum domain, enum language lang, --@@ -1212,17 +1214,30 @@ lookup_symbol_in_language (const char *n -- is_a_field_of_this); -- do_cleanups (cleanup); -- --+#ifdef CRASH_MERGE --+ if (returnval && (domain == VAR_DOMAIN)) --+ gdb_bait_and_switch((char *)modified_name, returnval); --+#endif --+ -- return returnval; -- } -- -- /* Behave like lookup_symbol_in_language, but performed with the -- current language. */ -- --+#ifdef CRASH_MERGE --+static struct block *gdb_get_crash_block(void); --+#endif --+ -- struct symbol * -- lookup_symbol (const char *name, const struct block *block, -- domain_enum domain, -- struct field_of_this_result *is_a_field_of_this) -- { --+#ifdef CRASH_MERGE --+ if (!block) --+ block = gdb_get_crash_block(); --+#endif -- return lookup_symbol_in_language (name, block, domain, -- current_language->la_language, -- is_a_field_of_this); --@@ -5100,3 +5115,662 @@ When enabled, debugging messages are pri -- -- observer_attach_executable_changed (symtab_observer_executable_changed); -- } --+ --+#ifdef CRASH_MERGE --+#include "gdb-stabs.h" --+#include "version.h" --+#define GDB_COMMON --+#include "../../defs.h" --+ --+static void get_member_data(struct gnu_request *, struct type *); --+static void dump_enum(struct type *, struct gnu_request *); --+static void eval_enum(struct type *, struct gnu_request *); --+static void gdb_get_line_number(struct gnu_request *); --+static void gdb_get_datatype(struct gnu_request *); --+static void gdb_get_symbol_type(struct gnu_request *); --+static void gdb_command_exists(struct gnu_request *); --+static void gdb_debug_command(struct gnu_request *); --+static void gdb_function_numargs(struct gnu_request *); --+static void gdb_add_symbol_file(struct gnu_request *); --+static void gdb_delete_symbol_file(struct gnu_request *); --+static void gdb_patch_symbol_values(struct gnu_request *); --+extern void replace_ui_file_FILE(struct ui_file *, FILE *); --+static void get_user_print_option_address(struct gnu_request *); --+extern int get_frame_offset(CORE_ADDR); --+static void gdb_set_crash_block(struct gnu_request *); --+void gdb_command_funnel(struct gnu_request *); --+ --+struct objfile *gdb_kernel_objfile = { 0 }; --+ --+static ulong gdb_merge_flags = 0; --+#define KERNEL_SYMBOLS_PATCHED (0x1) --+ --+#undef STREQ --+#define STREQ(A, B) (A && B && (strcmp(A, B) == 0)) --+ --+/* --+ * All commands from above come through here. --+ */ --+void --+gdb_command_funnel(struct gnu_request *req) --+{ --+ struct symbol *sym; --+ --+ if (req->command != GNU_VERSION) { --+ replace_ui_file_FILE(gdb_stdout, req->fp); --+ replace_ui_file_FILE(gdb_stderr, req->fp); --+ do_cleanups(all_cleanups()); --+ } --+ --+ switch (req->command) --+ { --+ case GNU_VERSION: --+ req->buf = (char *)version; --+ break; --+ --+ case GNU_PASS_THROUGH: --+ execute_command(req->buf, --+ req->flags & GNU_FROM_TTY_OFF ? FALSE : TRUE); --+ break; --+ --+ case GNU_USER_PRINT_OPTION: --+ get_user_print_option_address(req); --+ break; --+ --+ case GNU_RESOLVE_TEXT_ADDR: --+ sym = find_pc_function(req->addr); --+ if (!sym || TYPE_CODE(sym->type) != TYPE_CODE_FUNC) --+ req->flags |= GNU_COMMAND_FAILED; --+ break; --+ --+ case GNU_DISASSEMBLE: --+ if (req->addr2) --+ sprintf(req->buf, "disassemble 0x%lx 0x%lx", --+ req->addr, req->addr2); --+ else --+ sprintf(req->buf, "disassemble 0x%lx", req->addr); --+ execute_command(req->buf, TRUE); --+ break; --+ --+ case GNU_ADD_SYMBOL_FILE: --+ gdb_add_symbol_file(req); --+ break; --+ --+ case GNU_DELETE_SYMBOL_FILE: --+ gdb_delete_symbol_file(req); --+ break; --+ --+ case GNU_GET_LINE_NUMBER: --+ gdb_get_line_number(req); --+ break; --+ --+ case GNU_GET_DATATYPE: --+ gdb_get_datatype(req); --+ break; --+ --+ case GNU_GET_SYMBOL_TYPE: --+ gdb_get_symbol_type(req); --+ break; --+ --+ case GNU_COMMAND_EXISTS: --+ gdb_command_exists(req); --+ break; --+ --+ case GNU_ALPHA_FRAME_OFFSET: --+ req->value = 0; --+ break; --+ --+ case GNU_FUNCTION_NUMARGS: --+ gdb_function_numargs(req); --+ break; --+ --+ case GNU_DEBUG_COMMAND: --+ gdb_debug_command(req); --+ break; --+ --+ case GNU_PATCH_SYMBOL_VALUES: --+ gdb_patch_symbol_values(req); --+ break; --+ --+ case GNU_SET_CRASH_BLOCK: --+ gdb_set_crash_block(req); --+ break; --+ --+ default: --+ req->flags |= GNU_COMMAND_FAILED; --+ break; --+ } --+} --+ --+/* --+ * Given a PC value, return the file and line number. --+ */ --+static void --+gdb_get_line_number(struct gnu_request *req) --+{ --+ struct symtab_and_line sal; --+ struct symbol *sym; --+ CORE_ADDR pc; --+ --+#define LASTCHAR(s) (s[strlen(s)-1]) --+ --+ /* --+ * Prime the addrmap pump. --+ */ --+ if (req->name) --+ sym = lookup_symbol(req->name, 0, VAR_DOMAIN, 0); --+ --+ pc = req->addr; --+ --+ sal = find_pc_line(pc, 0); --+ --+ if (!sal.symtab) { --+ req->buf[0] = '\0'; --+ return; --+ } --+ --+ if (sal.symtab->filename && sal.symtab->dirname) { --+ if (sal.symtab->filename[0] == '/') --+ sprintf(req->buf, "%s: %d", --+ sal.symtab->filename, sal.line); --+ else --+ sprintf(req->buf, "%s%s%s: %d", --+ sal.symtab->dirname, --+ LASTCHAR(sal.symtab->dirname) == '/' ? "" : "/", --+ sal.symtab->filename, sal.line); --+ } --+} --+ --+ --+/* --+ * General purpose routine for determining datatypes. --+ */ --+ --+static void --+gdb_get_datatype(struct gnu_request *req) --+{ --+ register struct cleanup *old_chain = NULL; --+ register struct type *type; --+ register struct type *typedef_type; --+ struct expression *expr; --+ struct symbol *sym; --+ register int i; --+ struct field *nextfield; --+ struct value *val; --+ --+ if (gdb_CRASHDEBUG(2)) --+ console("gdb_get_datatype [%s] (a)\n", req->name); --+ --+ req->typecode = TYPE_CODE_UNDEF; --+ --+ /* --+ * lookup_symbol() will pick up struct and union names. --+ */ --+ sym = lookup_symbol(req->name, 0, STRUCT_DOMAIN, 0); --+ if (sym) { --+ req->typecode = TYPE_CODE(sym->type); --+ req->length = TYPE_LENGTH(sym->type); --+ if (req->member) --+ get_member_data(req, sym->type); --+ --+ if (TYPE_CODE(sym->type) == TYPE_CODE_ENUM) { --+ if (req->flags & GNU_PRINT_ENUMERATORS) --+ dump_enum(sym->type, req); --+ } --+ --+ return; --+ } --+ --+ /* --+ * Otherwise parse the expression. --+ */ --+ if (gdb_CRASHDEBUG(2)) --+ console("gdb_get_datatype [%s] (b)\n", req->name); --+ --+ expr = parse_expression(req->name); --+ --+ old_chain = make_cleanup(free_current_contents, &expr); --+ --+ --+ switch (expr->elts[0].opcode) --+ { --+ case OP_VAR_VALUE: --+ if (gdb_CRASHDEBUG(2)) --+ console("expr->elts[0].opcode: OP_VAR_VALUE\n"); --+ type = expr->elts[2].symbol->type; --+ if (req->flags & GNU_VAR_LENGTH_TYPECODE) { --+ req->typecode = TYPE_CODE(type); --+ req->length = TYPE_LENGTH(type); --+ } --+ if (TYPE_CODE(type) == TYPE_CODE_ENUM) { --+ req->typecode = TYPE_CODE(type); --+ req->value = SYMBOL_VALUE(expr->elts[2].symbol); --+ req->tagname = (char *)TYPE_TAG_NAME(type); --+ if (!req->tagname) { --+ val = evaluate_type(expr); --+ eval_enum(value_type(val), req); --+ } --+ } --+ break; --+ --+ case OP_TYPE: --+ if (gdb_CRASHDEBUG(2)) --+ console("expr->elts[0].opcode: OP_TYPE\n"); --+ type = expr->elts[1].type; --+ --+ req->typecode = TYPE_CODE(type); --+ req->length = TYPE_LENGTH(type); --+ --+ if (TYPE_CODE(type) == TYPE_CODE_TYPEDEF) { --+ req->is_typedef = TYPE_CODE_TYPEDEF; --+ if ((typedef_type = check_typedef(type))) { --+ req->typecode = TYPE_CODE(typedef_type); --+ req->length = TYPE_LENGTH(typedef_type); --+ type = typedef_type; --+ } --+ } --+ --+ if (TYPE_CODE(type) == TYPE_CODE_ENUM) { --+ if (req->is_typedef) --+ if (req->flags & GNU_PRINT_ENUMERATORS) { --+ if (req->is_typedef) --+ fprintf_filtered(gdb_stdout, --+ "typedef "); --+ dump_enum(type, req); --+ } --+ } --+ --+ if (req->member) --+ get_member_data(req, type); --+ --+ break; --+ --+ default: --+ if (gdb_CRASHDEBUG(2)) --+ console("expr->elts[0].opcode: %d (?)\n", --+ expr->elts[0].opcode); --+ break; --+ --+ } --+ --+ do_cleanups(old_chain); --+} --+ --+/* --+ * More robust enum list dump that gdb's, showing the value of each --+ * identifier, each on its own line. --+ */ --+static void --+dump_enum(struct type *type, struct gnu_request *req) --+{ --+ register int i; --+ int len; --+ int lastval; --+ --+ len = TYPE_NFIELDS (type); --+ lastval = 0; --+ if (TYPE_TAG_NAME(type)) --+ fprintf_filtered(gdb_stdout, --+ "enum %s {\n", TYPE_TAG_NAME (type)); --+ else --+ fprintf_filtered(gdb_stdout, "enum {\n"); --+ --+ for (i = 0; i < len; i++) { --+ fprintf_filtered(gdb_stdout, " %s", --+ TYPE_FIELD_NAME (type, i)); --+ if (lastval != TYPE_FIELD_BITPOS (type, i)) { --+ fprintf_filtered (gdb_stdout, " = %d", --+ TYPE_FIELD_BITPOS (type, i)); --+ lastval = TYPE_FIELD_BITPOS (type, i); --+ } else --+ fprintf_filtered(gdb_stdout, " = %d", lastval); --+ fprintf_filtered(gdb_stdout, "\n"); --+ lastval++; --+ } --+ if (TYPE_TAG_NAME(type)) --+ fprintf_filtered(gdb_stdout, "};\n"); --+ else --+ fprintf_filtered(gdb_stdout, "} %s;\n", req->name); --+} --+ --+/* --+ * Given an enum type with no tagname, determine its value. --+ */ --+static void --+eval_enum(struct type *type, struct gnu_request *req) --+{ --+ register int i; --+ int len; --+ int lastval; --+ --+ len = TYPE_NFIELDS (type); --+ lastval = 0; --+ --+ for (i = 0; i < len; i++) { --+ if (lastval != TYPE_FIELD_BITPOS (type, i)) { --+ lastval = TYPE_FIELD_BITPOS (type, i); --+ } --+ if (STREQ(TYPE_FIELD_NAME(type, i), req->name)) { --+ req->tagname = "(unknown)"; --+ req->value = lastval; --+ return; --+ } --+ lastval++; --+ } --+} --+ --+/* --+ * Walk through a struct type's list of fields looking for the desired --+ * member field, and when found, return its relevant data. --+ */ --+static void --+get_member_data(struct gnu_request *req, struct type *type) --+{ --+ register short i; --+ struct field *nextfield; --+ short nfields; --+ struct type *typedef_type; --+ --+ req->member_offset = -1; --+ --+ nfields = TYPE_MAIN_TYPE(type)->nfields; --+ nextfield = TYPE_MAIN_TYPE(type)->flds_bnds.fields; --+ --+ if (nfields == 0) { --+ struct type *newtype; --+ newtype = lookup_transparent_type(req->name); --+ if (newtype) { --+ console("get_member_data(%s.%s): switching type from %lx to %lx\n", --+ req->name, req->member, type, newtype); --+ nfields = TYPE_MAIN_TYPE(newtype)->nfields; --+ nextfield = TYPE_MAIN_TYPE(newtype)->flds_bnds.fields; --+ } --+ } --+ --+ for (i = 0; i < nfields; i++) { --+ if (STREQ(req->member, nextfield->name)) { --+ req->member_offset = nextfield->loc.bitpos; --+ req->member_length = TYPE_LENGTH(nextfield->type); --+ req->member_typecode = TYPE_CODE(nextfield->type); --+ if ((req->member_typecode == TYPE_CODE_TYPEDEF) && --+ (typedef_type = check_typedef(nextfield->type))) --+ req->member_length = TYPE_LENGTH(typedef_type); --+ return; --+ } --+ nextfield++; --+ } --+} --+ --+/* --+ * Check whether a command exists. If it doesn't, the command will be --+ * returned indirectly via the error_hook. --+ */ --+static void --+gdb_command_exists(struct gnu_request *req) --+{ --+ extern struct cmd_list_element *cmdlist; --+ register struct cmd_list_element *c; --+ --+ req->value = FALSE; --+ c = lookup_cmd(&req->name, cmdlist, "", 0, 1); --+ req->value = TRUE; --+} --+ --+static void --+gdb_function_numargs(struct gnu_request *req) --+{ --+ struct symbol *sym; --+ --+ sym = find_pc_function(req->pc); --+ --+ if (!sym || TYPE_CODE(sym->type) != TYPE_CODE_FUNC) { --+ req->flags |= GNU_COMMAND_FAILED; --+ return; --+ } --+ --+ req->value = (ulong)TYPE_NFIELDS(sym->type); --+} --+ --+struct load_module *gdb_current_load_module = NULL; --+ --+static void --+gdb_add_symbol_file(struct gnu_request *req) --+{ --+ register struct objfile *loaded_objfile = NULL; --+ register struct objfile *objfile; --+ register struct minimal_symbol *m; --+ struct load_module *lm; --+ int external, subsequent, found; --+ off_t offset; --+ ulong value, adjusted; --+ struct symbol *sym; --+ struct expression *expr; --+ struct cleanup *old_chain; --+ int i; --+ int allsect = 0; --+ char *secname; --+ char buf[80]; --+ --+ gdb_current_load_module = lm = (struct load_module *)req->addr; --+ --+ req->name = lm->mod_namelist; --+ gdb_delete_symbol_file(req); --+ --+ if ((lm->mod_flags & MOD_NOPATCH) == 0) { --+ for (i = 0 ; i < lm->mod_sections; i++) { --+ if (STREQ(lm->mod_section_data[i].name, ".text") && --+ (lm->mod_section_data[i].flags & SEC_FOUND)) --+ allsect = 1; --+ } --+ --+ if (!allsect) { --+ sprintf(req->buf, "add-symbol-file %s 0x%lx %s", lm->mod_namelist, --+ lm->mod_text_start ? lm->mod_text_start : lm->mod_base, --+ lm->mod_flags & MOD_DO_READNOW ? "-readnow" : ""); --+ if (lm->mod_data_start) { --+ sprintf(buf, " -s .data 0x%lx", lm->mod_data_start); --+ strcat(req->buf, buf); --+ } --+ if (lm->mod_bss_start) { --+ sprintf(buf, " -s .bss 0x%lx", lm->mod_bss_start); --+ strcat(req->buf, buf); --+ } --+ if (lm->mod_rodata_start) { --+ sprintf(buf, " -s .rodata 0x%lx", lm->mod_rodata_start); --+ strcat(req->buf, buf); --+ } --+ } else { --+ sprintf(req->buf, "add-symbol-file %s 0x%lx %s", lm->mod_namelist, --+ lm->mod_text_start, lm->mod_flags & MOD_DO_READNOW ? --+ "-readnow" : ""); --+ for (i = 0; i < lm->mod_sections; i++) { --+ secname = lm->mod_section_data[i].name; --+ if ((lm->mod_section_data[i].flags & SEC_FOUND) && --+ !STREQ(secname, ".text")) { --+ sprintf(buf, " -s %s 0x%lx", secname, --+ lm->mod_section_data[i].offset + lm->mod_base); --+ strcat(req->buf, buf); --+ } --+ } --+ } --+ } --+ --+ if (gdb_CRASHDEBUG(1)) --+ fprintf_filtered(gdb_stdout, "%s\n", req->buf); --+ --+ execute_command(req->buf, FALSE); --+ --+ ALL_OBJFILES(objfile) { --+ if (same_file(objfile->name, lm->mod_namelist)) { --+ loaded_objfile = objfile; --+ break; --+ } --+ } --+ --+ if (!loaded_objfile) --+ req->flags |= GNU_COMMAND_FAILED; --+} --+ --+static void --+gdb_delete_symbol_file(struct gnu_request *req) --+{ --+ register struct objfile *objfile; --+ --+ ALL_OBJFILES(objfile) { --+ if (STREQ(objfile->name, req->name) || --+ same_file(objfile->name, req->name)) { --+ free_objfile(objfile); --+ break; --+ } --+ } --+ --+ if (gdb_CRASHDEBUG(2)) { --+ fprintf_filtered(gdb_stdout, "current object files:\n"); --+ ALL_OBJFILES(objfile) --+ fprintf_filtered(gdb_stdout, " %s\n", objfile->name); --+ } --+} --+ --+/* --+ * Walk through all minimal_symbols, patching their values with the --+ * correct addresses. --+ */ --+static void --+gdb_patch_symbol_values(struct gnu_request *req) --+{ --+ struct minimal_symbol *msymbol; --+ struct objfile *objfile; --+ --+ req->name = PATCH_KERNEL_SYMBOLS_START; --+ patch_kernel_symbol(req); --+ --+ ALL_MSYMBOLS (objfile, msymbol) --+ { --+ req->name = (char *)msymbol->ginfo.name; --+ req->addr = (ulong)(&SYMBOL_VALUE_ADDRESS(msymbol)); --+ if (!patch_kernel_symbol(req)) { --+ req->flags |= GNU_COMMAND_FAILED; --+ break; --+ } --+ } --+ --+ req->name = PATCH_KERNEL_SYMBOLS_STOP; --+ patch_kernel_symbol(req); --+ --+ clear_symtab_users(0); --+ gdb_merge_flags |= KERNEL_SYMBOLS_PATCHED; --+} --+ --+static void --+gdb_get_symbol_type(struct gnu_request *req) --+{ --+ struct expression *expr; --+ struct value *val; --+ struct cleanup *old_chain = NULL; --+ struct type *type; --+ struct type *target_type; --+ --+ req->typecode = TYPE_CODE_UNDEF; --+ --+ expr = parse_expression (req->name); --+ old_chain = make_cleanup (free_current_contents, &expr); --+ val = evaluate_type (expr); --+ --+ type = value_type(val); --+ --+ req->type_name = (char *)TYPE_MAIN_TYPE(type)->name; --+ req->typecode = TYPE_MAIN_TYPE(type)->code; --+ req->length = type->length; --+ target_type = TYPE_MAIN_TYPE(type)->target_type; --+ --+ if (target_type) { --+ req->target_typename = (char *)TYPE_MAIN_TYPE(target_type)->name; --+ req->target_typecode = TYPE_MAIN_TYPE(target_type)->code; --+ req->target_length = target_type->length; --+ } --+ --+ if (req->member) --+ get_member_data(req, type); --+ --+ do_cleanups (old_chain); --+} --+ --+static void --+gdb_debug_command(struct gnu_request *req) --+{ --+ --+} --+ --+/* --+ * Only necessary on "patched" kernel symbol sessions, and called only by --+ * lookup_symbol(), pull a symbol value bait-and-switch operation by altering --+ * either a data symbol's address value or a text symbol's block start address. --+ */ --+static void --+gdb_bait_and_switch(char *name, struct symbol *sym) --+{ --+ struct minimal_symbol *msym; --+ struct block *block; --+ --+ if ((gdb_merge_flags & KERNEL_SYMBOLS_PATCHED) && --+ (msym = lookup_minimal_symbol(name, NULL, gdb_kernel_objfile))) { --+ if (sym->aclass == LOC_BLOCK) { --+ block = (struct block *)SYMBOL_BLOCK_VALUE(sym); --+ BLOCK_START(block) = SYMBOL_VALUE_ADDRESS(msym); --+ } else --+ SYMBOL_VALUE_ADDRESS(sym) = SYMBOL_VALUE_ADDRESS(msym); --+ } --+} --+ --+#include "valprint.h" --+ --+void --+get_user_print_option_address(struct gnu_request *req) --+{ --+ extern struct value_print_options user_print_options; --+ --+ req->addr = 0; --+ --+ if (strcmp(req->name, "output_format") == 0) --+ req->addr = (ulong)&user_print_options.output_format; --+ if (strcmp(req->name, "print_max") == 0) --+ req->addr = (ulong)&user_print_options.print_max; --+ if (strcmp(req->name, "prettyprint_structs") == 0) --+ req->addr = (ulong)&user_print_options.prettyprint_structs; --+ if (strcmp(req->name, "prettyprint_arrays") == 0) --+ req->addr = (ulong)&user_print_options.prettyprint_arrays; --+ if (strcmp(req->name, "repeat_count_threshold") == 0) --+ req->addr = (ulong)&user_print_options.repeat_count_threshold; --+ if (strcmp(req->name, "stop_print_at_null") == 0) --+ req->addr = (ulong)&user_print_options.stop_print_at_null; --+ if (strcmp(req->name, "output_radix") == 0) --+ req->addr = (ulong)&output_radix; --+} --+ --+CORE_ADDR crash_text_scope; --+ --+static void --+gdb_set_crash_block(struct gnu_request *req) --+{ --+ if (!req->addr) { /* debug */ --+ crash_text_scope = 0; --+ return; --+ } --+ --+ if ((req->addr2 = (ulong)block_for_pc(req->addr))) --+ crash_text_scope = req->addr; --+ else { --+ crash_text_scope = 0; --+ req->flags |= GNU_COMMAND_FAILED; --+ } --+} --+ --+static struct block * --+gdb_get_crash_block(void) --+{ --+ if (crash_text_scope) --+ return block_for_pc(crash_text_scope); --+ else --+ return NULL; --+} --+#endif ----- gdb-7.6/gdb/c-typeprint.c.orig --+++ gdb-7.6/gdb/c-typeprint.c --@@ -1097,7 +1097,8 @@ c_type_print_base (struct type *type, st -- fprintf_filtered (stream, "static "); -- c_print_type (TYPE_FIELD_TYPE (type, i), -- TYPE_FIELD_NAME (type, i), --- stream, show - 1, level + 4, --+ stream, strlen(TYPE_FIELD_NAME (type, i)) ? --+ show - 1 : show, level + 4, -- &local_flags); -- if (!field_is_static (&TYPE_FIELD (type, i)) -- && TYPE_FIELD_PACKED (type, i)) ----- gdb-7.6/gdb/xml-syscall.c.orig --+++ gdb-7.6/gdb/xml-syscall.c --@@ -38,7 +38,11 @@ -- static void -- syscall_warn_user (void) -- { --+#ifdef CRASH_MERGE --+ static int have_warned = 1; --+#else -- static int have_warned = 0; --+#endif -- if (!have_warned) -- { -- have_warned = 1; ----- gdb-7.6/gdb/exceptions.c.orig --+++ gdb-7.6/gdb/exceptions.c --@@ -218,6 +218,10 @@ exceptions_state_mc_action_iter_1 (void) -- -- /* Return EXCEPTION to the nearest containing catch_errors(). */ -- --+#ifdef CRASH_MERGE --+void (*error_hook) (void) ATTRIBUTE_NORETURN; --+#endif --+ -- void -- throw_exception (struct gdb_exception exception) -- { --@@ -225,6 +229,13 @@ throw_exception (struct gdb_exception ex -- immediate_quit = 0; -- -- do_cleanups (all_cleanups ()); --+#ifdef CRASH_MERGE --+ if (error_hook) { --+ fprintf_filtered(gdb_stderr, "%s\n", exception.message); --+ (*error_hook)(); --+ } else --+ fprintf_filtered(gdb_stderr, "gdb called without error_hook: %s\n", exception.message); --+#endif -- -- /* Jump to the containing catch_errors() call, communicating REASON -- to that call via setjmp's return value. Note that REASON can't ----- gdb-7.6/gdb/valprint.h.orig --+++ gdb-7.6/gdb/valprint.h --@@ -152,11 +152,17 @@ extern void print_function_pointer_addre -- struct gdbarch *gdbarch, -- CORE_ADDR address, -- struct ui_file *stream); --- --+#ifdef CRASH_MERGE --+extern int valprint_read_string (CORE_ADDR addr, int len, int width, --+ unsigned int fetchlimit, --+ enum bfd_endian byte_order, gdb_byte **buffer, --+ int *bytes_read); --+#else -- extern int read_string (CORE_ADDR addr, int len, int width, -- unsigned int fetchlimit, -- enum bfd_endian byte_order, gdb_byte **buffer, -- int *bytes_read); --+#endif -- -- extern void val_print_optimized_out (struct ui_file *stream); -- ----- gdb-7.6/gdb/target.c.orig --+++ gdb-7.6/gdb/target.c --@@ -1779,6 +1779,13 @@ target_xfer_partial (struct target_ops * -- int -- target_read_memory (CORE_ADDR memaddr, gdb_byte *myaddr, ssize_t len) -- { --+#ifdef CRASH_MERGE --+ extern int gdb_readmem_callback(unsigned long, void *, int, int); --+ if (gdb_readmem_callback(memaddr, (void *)myaddr, len, 0)) --+ return 0; --+ else --+ return EIO; --+#endif -- /* Dispatch to the topmost target, not the flattened current_target. -- Memory accesses check target->to_has_(all_)memory, and the -- flattened target doesn't inherit those. */ --@@ -1814,6 +1821,13 @@ target_read_stack (CORE_ADDR memaddr, gd -- int -- target_write_memory (CORE_ADDR memaddr, const gdb_byte *myaddr, ssize_t len) -- { --+#ifdef CRASH_MERGE --+ extern int gdb_readmem_callback(unsigned long, void *, int, int); --+ if (gdb_readmem_callback(memaddr, (void *)myaddr, len, 1)) --+ return 0; --+ else --+ return EIO; --+#endif -- /* Dispatch to the topmost target, not the flattened current_target. -- Memory accesses check target->to_has_(all_)memory, and the -- flattened target doesn't inherit those. */ ----- gdb-7.6/gdb/printcmd.c.orig --+++ gdb-7.6/gdb/printcmd.c --@@ -1001,11 +1001,62 @@ print_command_1 (char *exp, int voidprin -- } -- -- static void --+print_command_2 (char *exp, int inspect, int voidprint) --+{ --+ struct expression *expr; --+ struct cleanup *old_chain = 0; --+ char format = 0; --+ struct value *val; --+ struct format_data fmt; --+ int cleanup = 0; --+ --+ if (exp && *exp == '/') --+ { --+ exp++; --+ fmt = decode_format (&exp, last_format, 0); --+ validate_format (fmt, "print"); --+ last_format = format = fmt.format; --+ } --+ else --+ { --+ fmt.count = 1; --+ fmt.format = 0; --+ fmt.size = 0; --+ fmt.raw = 0; --+ } --+ --+ if (exp && *exp) --+ { --+ expr = parse_expression (exp); --+ old_chain = make_cleanup (free_current_contents, &expr); --+ cleanup = 1; --+ val = evaluate_expression (expr); --+ } --+ else --+ val = access_value_history (0); --+ --+ printf_filtered ("%d %d %d %d %d %d\n", --+ TYPE_CODE (check_typedef(value_type (val))), --+ TYPE_UNSIGNED (check_typedef(value_type (val))), --+ TYPE_LENGTH (check_typedef(value_type(val))), --+ value_offset (val), value_bitpos (val), value_bitsize(val)); --+ --+ if (cleanup) --+ do_cleanups (old_chain); --+} --+ --+static void -- print_command (char *exp, int from_tty) -- { -- print_command_1 (exp, 1); -- } -- --+static void --+printm_command (char *exp, int from_tty) --+{ --+ print_command_2 (exp, 0, 1); --+} --+ -- /* Same as print, except it doesn't print void results. */ -- static void -- call_command (char *exp, int from_tty) --@@ -2593,6 +2644,12 @@ EXP may be preceded with /FMT, where FMT -- but no count or size letter (see \"x\" command).")); -- set_cmd_completer (c, expression_completer); -- add_com_alias ("p", "print", class_vars, 1); --+ --+ c = add_com ("printm", class_vars, printm_command, _("\ --+Similar to \"print\" command, but it used to print the type, size, offset,\n\ --+bitpos and bitsize of the expression EXP.")); --+ set_cmd_completer (c, expression_completer); --+ -- add_com_alias ("inspect", "print", class_vars, 1); -- -- add_setshow_uinteger_cmd ("max-symbolic-offset", no_class, ----- gdb-7.6/gdb/ui-file.c.orig --+++ gdb-7.6/gdb/ui-file.c --@@ -671,6 +671,17 @@ gdb_fopen (char *name, char *mode) -- return stdio_file_new (f, 1); -- } -- --+#ifdef CRASH_MERGE --+void --+replace_ui_file_FILE(struct ui_file *file, FILE *fp) --+{ --+ struct stdio_file *stdio_file; --+ --+ stdio_file = (struct stdio_file *)ui_file_data(file); --+ stdio_file->file = fp; --+} --+#endif --+ -- /* ``struct ui_file'' implementation that maps onto two ui-file objects. */ -- -- static ui_file_write_ftype tee_file_write; ----- gdb-7.6/gdb/main.c.orig --+++ gdb-7.6/gdb/main.c --@@ -806,7 +806,7 @@ captured_main (void *data) -- { -- print_gdb_version (gdb_stdout); -- wrap_here (""); --- printf_filtered ("\n"); --+ printf_filtered ("\n\n"); -- exit (0); -- } -- --@@ -853,6 +853,13 @@ captured_main (void *data) -- } -- } -- --+#ifdef CRASH_MERGE --+{ --+ extern void update_gdb_hooks(void); --+ update_gdb_hooks(); --+} --+#endif --+ -- /* FIXME: cagney/2003-02-03: The big hack (part 2 of 2) that lets -- GDB retain the old MI1 interpreter startup behavior. Output the -- copyright message after the interpreter is installed when it is --@@ -880,7 +887,11 @@ captured_main (void *data) -- processed; it sets global parameters, which are independent of -- what file you are debugging or what directory you are in. */ -- if (system_gdbinit && !inhibit_gdbinit) --+#ifdef CRASH_MERGE --+ catch_command_errors (source_script, system_gdbinit, -1, RETURN_MASK_ALL); --+#else -- catch_command_errors (source_script, system_gdbinit, 0, RETURN_MASK_ALL); --+#endif -- -- /* Read and execute $HOME/.gdbinit file, if it exists. This is done -- *before* all the command line arguments are processed; it sets --@@ -888,7 +899,11 @@ captured_main (void *data) -- debugging or what directory you are in. */ -- -- if (home_gdbinit && !inhibit_gdbinit && !inhibit_home_gdbinit) --+#ifdef CRASH_MERGE --+ catch_command_errors (source_script, home_gdbinit, -1, RETURN_MASK_ALL); --+#else -- catch_command_errors (source_script, home_gdbinit, 0, RETURN_MASK_ALL); --+#endif -- -- /* Process '-ix' and '-iex' options early. */ -- for (i = 0; VEC_iterate (cmdarg_s, cmdarg_vec, i, cmdarg_p); i++) --@@ -929,8 +944,12 @@ captured_main (void *data) -- catch_command_errors returns non-zero on success! */ -- if (catch_command_errors (exec_file_attach, execarg, -- !batch_flag, RETURN_MASK_ALL)) --+#ifdef CRASH_MERGE --+ catch_command_errors (symbol_file_add_main, symarg, 0, RETURN_MASK_ALL); --+#else -- catch_command_errors (symbol_file_add_main, symarg, -- !batch_flag, RETURN_MASK_ALL); --+#endif -- } -- else -- { --@@ -992,8 +1011,12 @@ captured_main (void *data) -- { -- auto_load_local_gdbinit_loaded = 1; -- --+#ifdef CRASH_MERGE --+ catch_command_errors (source_script, local_gdbinit, -1, RETURN_MASK_ALL); --+#else -- catch_command_errors (source_script, local_gdbinit, 0, -- RETURN_MASK_ALL); --+#endif -- } -- } -- --@@ -1039,6 +1062,12 @@ captured_main (void *data) -- while (1) -- { -- catch_errors (captured_command_loop, 0, "", RETURN_MASK_ALL); --+#ifdef CRASH_MERGE --+ { --+ int console(char *, ...); --+ console("\n"); --+ } --+#endif -- } -- /* No exit -- exit is through quit_command. */ -- } --@@ -1053,6 +1082,23 @@ gdb_main (struct captured_main_args *arg -- return 1; -- } -- --+#ifdef CRASH_MERGE --+/* --+ * NOTE: adapted from gdb.c, which is no longer built in; changed name of --+ * original main() to gdb_main_entry() for use as crash entry point --+ */ --+int --+gdb_main_entry (int argc, char **argv) --+{ --+ struct captured_main_args args; --+ memset (&args, 0, sizeof args); --+ args.argc = argc; --+ args.argv = argv; --+ args.use_windows = 0; --+ args.interpreter_p = INTERP_CONSOLE; --+ return gdb_main (&args); --+} --+#endif -- -- /* Don't use *_filtered for printing help. We don't want to prompt -- for continue no matter how small the screen or how much we're going ----- gdb-7.6/gdb/valprint.c.orig --+++ gdb-7.6/gdb/valprint.c --@@ -1768,8 +1768,13 @@ partial_memory_read (CORE_ADDR memaddr, -- this function instead? */ -- -- int --+#ifdef CRASH_MERGE --+valprint_read_string (CORE_ADDR addr, int len, int width, unsigned int fetchlimit, --+ enum bfd_endian byte_order, gdb_byte **buffer, int *bytes_read) --+#else -- read_string (CORE_ADDR addr, int len, int width, unsigned int fetchlimit, -- enum bfd_endian byte_order, gdb_byte **buffer, int *bytes_read) --+#endif -- { -- int found_nul; /* Non-zero if we found the nul char. */ -- int errcode; /* Errno returned from bad reads. */ --@@ -2472,8 +2477,13 @@ val_print_string (struct type *elttype, -- fetchlimit = (len == -1 ? options->print_max : min (len, -- options->print_max)); -- --+#ifdef CRASH_MERGE --+ errcode = valprint_read_string (addr, len, width, fetchlimit, byte_order, --+ &buffer, &bytes_read); --+#else -- errcode = read_string (addr, len, width, fetchlimit, byte_order, -- &buffer, &bytes_read); --+#endif -- old_chain = make_cleanup (xfree, buffer); -- -- addr += bytes_read; ----- gdb-7.6/gdb/Makefile.in.orig --+++ gdb-7.6/gdb/Makefile.in --@@ -422,7 +422,7 @@ CONFIG_UNINSTALL = @CONFIG_UNINSTALL@ -- # It is also possible that you will need to add -I/usr/include/sys if -- # your system doesn't have fcntl.h in /usr/include (which is where it -- # should be according to Posix). ---DEFS = @DEFS@ --+DEFS = -DCRASH_MERGE @DEFS@ -- GDB_CFLAGS = -I. -I$(srcdir) -I$(srcdir)/common -I$(srcdir)/config \ -- -DLOCALEDIR="\"$(localedir)\"" $(DEFS) -- --@@ -934,7 +934,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $ -- -- TSOBS = inflow.o -- ---SUBDIRS = doc @subdirs@ data-directory $(GNULIB_BUILDDIR) --+SUBDIRS = build_no_subdirs -- CLEANDIRS = $(SUBDIRS) -- -- # List of subdirectories in the build tree that must exist. --@@ -969,8 +969,8 @@ generated_files = config.h observer.h ob -- $(COMPILE) $< -- $(POSTCOMPILE) -- ---all: gdb$(EXEEXT) $(CONFIG_ALL) --- @$(MAKE) $(FLAGS_TO_PASS) DO=all "DODIRS=`echo $(SUBDIRS) | sed 's/testsuite//'`" subdir_do --+all: gdb$(EXEEXT) --+ @$(MAKE) -s $(FLAGS_TO_PASS) DO=all "DODIRS=`echo $(SUBDIRS) | sed 's/testsuite//'`" subdir_do -- -- installcheck: -- --@@ -1172,15 +1172,16 @@ libgdb.a: $(LIBGDB_OBS) -- -- # Removing the old gdb first works better if it is running, at least on SunOS. -- gdb$(EXEEXT): gdb.o $(LIBGDB_OBS) $(ADD_DEPS) $(CDEPS) $(TDEPLIBS) --- rm -f gdb$(EXEEXT) --+ @rm -f gdb$(EXEEXT) --+ @(cd ../..; make --no-print-directory GDB_FLAGS=-DGDB_7_6 library) -- $(CC_LD) $(INTERNAL_LDFLAGS) $(WIN32LDAPP) \ --- -o gdb$(EXEEXT) gdb.o $(LIBGDB_OBS) \ --- $(TDEPLIBS) $(TUI_LIBRARY) $(CLIBS) $(LOADLIBES) --+ -o $(shell /bin/cat mergeobj) $(LIBGDB_OBS) \ --+ $(TDEPLIBS) $(TUI_LIBRARY) $(CLIBS) $(LOADLIBES) $(shell /bin/cat mergelibs) -- -- # Convenience rule to handle recursion. -- $(LIBGNU) $(GNULIB_H): all-lib -- all-lib: $(GNULIB_BUILDDIR)/Makefile --- @$(MAKE) $(FLAGS_TO_PASS) DO=all DODIRS=$(GNULIB_BUILDDIR) subdir_do --+ @$(MAKE) $(FLAGS_TO_PASS) DO=all DODIRS=$(GNULIB_BUILDDIR) subdir_do -s -- .PHONY: all-lib -- -- # Convenience rule to handle recursion. --@@ -1389,12 +1390,12 @@ $(srcdir)/copying.c: @MAINTAINER_MODE_TR -- mv $(srcdir)/copying.tmp $(srcdir)/copying.c -- -- version.c: Makefile version.in --- rm -f version.c-tmp version.c --- echo '#include "version.h"' >> version.c-tmp --- echo 'const char version[] = "'"`sed q ${srcdir}/version.in`"'";' >> version.c-tmp --- echo 'const char host_name[] = "$(host_alias)";' >> version.c-tmp --- echo 'const char target_name[] = "$(target_alias)";' >> version.c-tmp --- mv version.c-tmp version.c --+ @rm -f version.c-tmp version.c --+ @echo '#include "version.h"' >> version.c-tmp --+ @echo 'const char version[] = "'"`sed q ${srcdir}/version.in`"'";' >> version.c-tmp --+ @echo 'const char host_name[] = "$(host_alias)";' >> version.c-tmp --+ @echo 'const char target_name[] = "$(target_alias)";' >> version.c-tmp --+ @mv version.c-tmp version.c -- -- observer.h: observer.sh doc/observer.texi -- ${srcdir}/observer.sh h ${srcdir}/doc/observer.texi observer.h ----- gdb-7.6/gdb/c-lang.c.orig --+++ gdb-7.6/gdb/c-lang.c --@@ -307,7 +307,11 @@ c_get_string (struct value *value, gdb_b -- { -- CORE_ADDR addr = value_as_address (value); -- --+#ifdef CRASH_MERGE --+ err = valprint_read_string (addr, *length, width, fetchlimit, --+#else -- err = read_string (addr, *length, width, fetchlimit, --+#endif -- byte_order, buffer, length); -- if (err) -- { ----- gdb-7.6/readline/rltypedefs.h.orig --+++ gdb-7.6/readline/rltypedefs.h --@@ -31,10 +31,10 @@ extern "C" { -- #if !defined (_FUNCTION_DEF) -- # define _FUNCTION_DEF -- ---typedef int Function (); ---typedef void VFunction (); ---typedef char *CPFunction (); ---typedef char **CPPFunction (); --+typedef int Function (void); --+typedef void VFunction (void); --+typedef char *CPFunction (void); --+typedef char **CPPFunction (void); -- -- #endif /* _FUNCTION_DEF */ -- ----- gdb-7.6/readline/readline.h.orig --+++ gdb-7.6/readline/readline.h --@@ -378,7 +378,7 @@ extern int rl_crlf PARAMS((void)); -- #if defined (USE_VARARGS) && defined (PREFER_STDARG) -- extern int rl_message (const char *, ...) __attribute__((__format__ (printf, 1, 2))); -- #else ---extern int rl_message (); --+extern int rl_message (void); -- #endif -- -- extern int rl_show_char PARAMS((int)); ----- gdb-7.6/readline/misc.c.orig --+++ gdb-7.6/readline/misc.c --@@ -405,7 +405,7 @@ _rl_history_set_point () -- -- #if defined (VI_MODE) -- if (rl_editing_mode == vi_mode && _rl_keymap != vi_insertion_keymap) --- rl_point = 0; --+ rl_point = rl_end; -- #endif /* VI_MODE */ -- -- if (rl_editing_mode == emacs_mode) ----- gdb-7.6/Makefile.in.orig --+++ gdb-7.6/Makefile.in --@@ -342,6 +342,9 @@ AR_FOR_BUILD = @AR_FOR_BUILD@ -- AS_FOR_BUILD = @AS_FOR_BUILD@ -- CC_FOR_BUILD = @CC_FOR_BUILD@ -- CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@ --+ifeq (${CRASH_TARGET}, PPC64) --+CFLAGS_FOR_BUILD += -m64 -fPIC --+endif -- CXXFLAGS_FOR_BUILD = @CXXFLAGS_FOR_BUILD@ -- CXX_FOR_BUILD = @CXX_FOR_BUILD@ -- DLLTOOL_FOR_BUILD = @DLLTOOL_FOR_BUILD@ --@@ -407,6 +410,9 @@ GNATBIND = @GNATBIND@ -- GNATMAKE = @GNATMAKE@ -- -- CFLAGS = @CFLAGS@ --+ifeq (${CRASH_TARGET}, PPC64) --+CFLAGS += -m64 -fPIC --+endif -- LDFLAGS = @LDFLAGS@ -- LIBCFLAGS = $(CFLAGS) -- CXXFLAGS = @CXXFLAGS@ ----- gdb-7.6/gdb/defs.h.orig --+++ gdb-7.6/gdb/defs.h --@@ -802,4 +802,8 @@ enum block_enum -- -- #include "utils.h" -- --+#ifdef CRASH_MERGE --+extern int gdb_main_entry(int, char **); --+extern void replace_ui_file_FILE(struct ui_file *, FILE *); --+#endif -- #endif /* #ifndef DEFS_H */ ----- gdb-7.6/bfd/elflink.c.orig --+++ gdb-7.6/bfd/elflink.c --@@ -4730,7 +4730,7 @@ error_free_dyn: -- struct elf_link_hash_entry *hlook; -- asection *slook; -- bfd_vma vlook; --- size_t i, j, idx; --+ size_t i, j, idx = 0; -- -- hlook = weaks; -- weaks = hlook->u.weakdef; ----- gdb-7.6/gdb/s390-nat.c.orig --+++ gdb-7.6/gdb/s390-nat.c --@@ -37,6 +37,8 @@ -- #include -- #include -- --+#include --+ -- #ifndef HWCAP_S390_HIGH_GPRS -- #define HWCAP_S390_HIGH_GPRS 512 -- #endif ----- gdb-7.6/gdb/printcmd.c.orig --+++ gdb-7.6/gdb/printcmd.c --@@ -573,11 +573,21 @@ print_address_symbolic (struct gdbarch * -- int unmapped = 0; -- int offset = 0; -- int line = 0; --+#ifdef CRASH_MERGE --+ extern int gdb_print_callback(unsigned long); --+#endif -- -- /* Throw away both name and filename. */ -- struct cleanup *cleanup_chain = make_cleanup (free_current_contents, &name); -- make_cleanup (free_current_contents, &filename); -- --+#ifdef CRASH_MERGE --+ if (!gdb_print_callback(addr)) { --+ do_cleanups (cleanup_chain); --+ return 0; --+ } --+#endif --+ -- if (build_address_symbolic (gdbarch, addr, do_demangle, &name, &offset, -- &filename, &line, &unmapped)) -- { ----- gdb-7.6/bfd/bfd-in.h.orig --+++ gdb-7.6/bfd/bfd-in.h --@@ -294,9 +294,6 @@ typedef struct bfd_section *sec_ptr; -- -- #define bfd_is_com_section(ptr) (((ptr)->flags & SEC_IS_COMMON) != 0) -- ---#define bfd_set_section_vma(bfd, ptr, val) (((ptr)->vma = (ptr)->lma = (val)), ((ptr)->user_set_vma = TRUE), TRUE) ---#define bfd_set_section_alignment(bfd, ptr, val) (((ptr)->alignment_power = (val)),TRUE) ---#define bfd_set_section_userdata(bfd, ptr, val) (((ptr)->userdata = (val)),TRUE) -- /* Find the address one past the end of SEC. */ -- #define bfd_get_section_limit(bfd, sec) \ -- (((bfd)->direction != write_direction && (sec)->rawsize != 0 \ --@@ -519,7 +516,6 @@ extern void warn_deprecated (const char -- -- #define bfd_get_symbol_leading_char(abfd) ((abfd)->xvec->symbol_leading_char) -- ---#define bfd_set_cacheable(abfd,bool) (((abfd)->cacheable = bool), TRUE) -- -- extern bfd_boolean bfd_cache_close -- (bfd *abfd); ----- gdb-7.6/bfd/bfd-in2.h.orig --+++ gdb-7.6/bfd/bfd-in2.h --@@ -301,9 +301,6 @@ typedef struct bfd_section *sec_ptr; -- -- #define bfd_is_com_section(ptr) (((ptr)->flags & SEC_IS_COMMON) != 0) -- ---#define bfd_set_section_vma(bfd, ptr, val) (((ptr)->vma = (ptr)->lma = (val)), ((ptr)->user_set_vma = TRUE), TRUE) ---#define bfd_set_section_alignment(bfd, ptr, val) (((ptr)->alignment_power = (val)),TRUE) ---#define bfd_set_section_userdata(bfd, ptr, val) (((ptr)->userdata = (val)),TRUE) -- /* Find the address one past the end of SEC. */ -- #define bfd_get_section_limit(bfd, sec) \ -- (((bfd)->direction != write_direction && (sec)->rawsize != 0 \ --@@ -526,7 +523,6 @@ extern void warn_deprecated (const char -- -- #define bfd_get_symbol_leading_char(abfd) ((abfd)->xvec->symbol_leading_char) -- ---#define bfd_set_cacheable(abfd,bool) (((abfd)->cacheable = bool), TRUE) -- -- extern bfd_boolean bfd_cache_close -- (bfd *abfd); --@@ -1572,6 +1568,32 @@ struct relax_table { -- int size; -- }; -- --+/* Note: the following are provided as inline functions rather than macros --+ because not all callers use the return value. A macro implementation --+ would use a comma expression, eg: "((ptr)->foo = val, TRUE)" and some --+ compilers will complain about comma expressions that have no effect. */ --+static inline bfd_boolean --+bfd_set_section_userdata (bfd * abfd ATTRIBUTE_UNUSED, asection * ptr, void * val) --+{ --+ ptr->userdata = val; --+ return TRUE; --+} --+ --+static inline bfd_boolean --+bfd_set_section_vma (bfd * abfd ATTRIBUTE_UNUSED, asection * ptr, bfd_vma val) --+{ --+ ptr->vma = ptr->lma = val; --+ ptr->user_set_vma = TRUE; --+ return TRUE; --+} --+ --+static inline bfd_boolean --+bfd_set_section_alignment (bfd * abfd ATTRIBUTE_UNUSED, asection * ptr, unsigned int val) --+{ --+ ptr->alignment_power = val; --+ return TRUE; --+} --+ -- /* These sections are global, and are managed by BFD. The application -- and target back end are not permitted to change the values in -- these sections. */ --@@ -6095,6 +6117,14 @@ struct bfd -- unsigned int selective_search : 1; -- }; -- --+/* See note beside bfd_set_section_userdata. */ --+static inline bfd_boolean --+bfd_set_cacheable (bfd * abfd, bfd_boolean val) --+{ --+ abfd->cacheable = val; --+ return TRUE; --+} --+ -- typedef enum bfd_error -- { -- bfd_error_no_error = 0, ----- gdb-7.6/gdb/symtab.c.orig --+++ gdb-7.6/gdb/symtab.c --@@ -5405,7 +5405,7 @@ dump_enum(struct type *type, struct gnu_ -- { -- register int i; -- int len; --- int lastval; --+ long long lastval; -- -- len = TYPE_NFIELDS (type); -- lastval = 0; --@@ -5418,12 +5418,12 @@ dump_enum(struct type *type, struct gnu_ -- for (i = 0; i < len; i++) { -- fprintf_filtered(gdb_stdout, " %s", -- TYPE_FIELD_NAME (type, i)); --- if (lastval != TYPE_FIELD_BITPOS (type, i)) { --- fprintf_filtered (gdb_stdout, " = %d", --- TYPE_FIELD_BITPOS (type, i)); --- lastval = TYPE_FIELD_BITPOS (type, i); --+ if (lastval != TYPE_FIELD_ENUMVAL (type, i)) { --+ fprintf_filtered (gdb_stdout, " = %s", --+ plongest(TYPE_FIELD_ENUMVAL (type, i))); --+ lastval = TYPE_FIELD_ENUMVAL (type, i); -- } else --- fprintf_filtered(gdb_stdout, " = %d", lastval); --+ fprintf_filtered(gdb_stdout, " = %s", plongest(lastval)); -- fprintf_filtered(gdb_stdout, "\n"); -- lastval++; -- } ----- gdb-7.6/gdb/aarch64-linux-nat.c.orig --+++ gdb-7.6/gdb/aarch64-linux-nat.c --@@ -32,6 +32,7 @@ -- #include "elf/common.h" -- -- #include --+#include -- #include -- -- #include "gregset.h" ----- gdb-7.6/sim/igen/Makefile.in.orig --+++ gdb-7.6/sim/igen/Makefile.in --@@ -117,7 +117,7 @@ IGEN_OBJS=\ -- gen.o -- -- igen: igen.o $(IGEN_OBJS) --- $(CC_FOR_BUILD) $(BUILD_LDFLAGS) -o igen igen.o $(IGEN_OBJS) $(LIBIBERTY_LIB) --+ $(CC_FOR_BUILD) $(BUILD_CFLAGS) $(BUILD_LDFLAGS) -o igen igen.o $(IGEN_OBJS) $(LIBIBERTY_LIB) -- -- igen.o: igen.c misc.h filter_host.h lf.h table.h ld-decode.h ld-cache.h ld-insn.h filter.h gen-model.h gen-itable.h gen-icache.h gen-idecode.h gen-engine.h gen-semantics.h gen-support.h gen.h igen.h -- $(CC_FOR_BUILD) $(BUILD_CFLAGS) -c $(srcdir)/igen.c ----- gdb-7.6/sim/mips/cp1.c.orig --+++ gdb-7.6/sim/mips/cp1.c --@@ -1359,7 +1359,7 @@ fp_rsqrt2(sim_cpu *cpu, -- /* Conversion operations. */ -- -- uword64 ---convert (sim_cpu *cpu, --+sim_mips_convert (sim_cpu *cpu, -- address_word cia, -- int rm, -- uword64 op, ----- gdb-7.6/sim/mips/sim-main.h.orig --+++ gdb-7.6/sim/mips/sim-main.h --@@ -770,8 +770,8 @@ unsigned64 fp_nmadd (SIM_STATE, unsigned64 op1, unsigned64 op2, -- unsigned64 fp_nmsub (SIM_STATE, unsigned64 op1, unsigned64 op2, -- unsigned64 op3, FP_formats fmt); -- #define NegMultiplySub(op1,op2,op3,fmt) fp_nmsub(SIM_ARGS, op1, op2, op3, fmt) ---unsigned64 convert (SIM_STATE, int rm, unsigned64 op, FP_formats from, FP_formats to); ---#define Convert(rm,op,from,to) convert (SIM_ARGS, rm, op, from, to) --+unsigned64 sim_mips_convert (SIM_STATE, int rm, unsigned64 op, FP_formats from, FP_formats to); --+#define Convert(rm,op,from,to) sim_mips_convert (SIM_ARGS, rm, op, from, to) -- unsigned64 convert_ps (SIM_STATE, int rm, unsigned64 op, FP_formats from, -- FP_formats to); -- #define ConvertPS(rm,op,from,to) convert_ps (SIM_ARGS, rm, op, from, to) -- ----- gdb-7.6/readline/util.c --+++ gdb-7.6/readline/util.c --@@ -493,10 +493,13 @@ _rl_trace (va_alist) -- -- if (_rl_tracefp == 0) -- _rl_tropen (); --+ if (!_rl_tracefp) --+ goto out; -- vfprintf (_rl_tracefp, format, args); -- fprintf (_rl_tracefp, "\n"); -- fflush (_rl_tracefp); -- --+out: -- va_end (args); -- } -- --@@ -509,16 +512,17 @@ _rl_tropen () -- fclose (_rl_tracefp); -- sprintf (fnbuf, "/var/tmp/rltrace.%ld", getpid()); -- unlink(fnbuf); --- _rl_tracefp = fopen (fnbuf, "w+"); --+ _rl_tracefp = fopen (fnbuf, "w+xe"); -- return _rl_tracefp != 0; -- } -- -- int -- _rl_trclose () -- { --- int r; --+ int r = 0; -- --- r = fclose (_rl_tracefp); --+ if (_rl_tracefp) --+ r = fclose (_rl_tracefp); -- _rl_tracefp = 0; -- return r; -- } ----- gdb-7.6/gdb/symtab.c.orig --+++ gdb-7.6/gdb/symtab.c --@@ -5447,9 +5447,9 @@ eval_enum(struct type *type, struct gnu_ -- lastval = 0; -- -- for (i = 0; i < len; i++) { --- if (lastval != TYPE_FIELD_BITPOS (type, i)) { --- lastval = TYPE_FIELD_BITPOS (type, i); --- } --+ if (lastval != TYPE_FIELD_ENUMVAL (type, i)) --+ lastval = TYPE_FIELD_ENUMVAL (type, i); --+ -- if (STREQ(TYPE_FIELD_NAME(type, i), req->name)) { -- req->tagname = "(unknown)"; -- req->value = lastval; ----- gdb-7.6/gdb/symtab.c.orig --+++ gdb-7.6/gdb/symtab.c --@@ -5236,6 +5236,12 @@ gdb_command_funnel(struct gnu_request *r -- gdb_set_crash_block(req); -- break; -- --+ case GNU_GET_FUNCTION_RANGE: --+ sym = lookup_symbol(req->name, 0, VAR_DOMAIN, 0); --+ if (!find_pc_partial_function(req->pc, NULL, &req->addr, &req->addr2)) --+ req->flags |= GNU_COMMAND_FAILED; --+ break; --+ -- default: -- req->flags |= GNU_COMMAND_FAILED; -- break; ----- gdb-7.6/opcodes/i386-dis.c.orig --+++ gdb-7.6/opcodes/i386-dis.c --@@ -11300,6 +11300,29 @@ get_sib (disassemble_info *info) -- } -- } -- --+static char * --+check_for_extensions(struct dis_private *priv) --+{ --+ unsigned char ModRM; --+ --+ if ((priv->the_buffer[0] == 0x66) && --+ (priv->the_buffer[1] == 0x0f) && --+ (priv->the_buffer[2] == 0xae)) { --+ ModRM = priv->the_buffer[3]; --+ if (ModRM == 0xf8) --+ return "pcommit"; --+ --+ switch ((ModRM >> 3)) --+ { --+ case 0x6: --+ return "clwb"; --+ case 0x7: --+ return "clflushopt"; --+ } --+ } --+ return NULL; --+} --+ -- static int -- print_insn (bfd_vma pc, disassemble_info *info) -- { --@@ -11312,6 +11335,7 @@ print_insn (bfd_vma pc, disassemble_info -- struct dis_private priv; -- int prefix_length; -- int default_prefixes; --+ char *extension; -- -- priv.orig_sizeflag = AFLAG | DFLAG; -- if ((info->mach & bfd_mach_i386_i386) != 0) --@@ -11575,6 +11599,7 @@ print_insn (bfd_vma pc, disassemble_info -- need_vex = 0; -- need_vex_reg = 0; -- vex_w_done = 0; --+ extension = NULL; -- -- if (dp->name == NULL && dp->op[0].bytemode == FLOATCODE) -- { --@@ -11610,9 +11635,14 @@ print_insn (bfd_vma pc, disassemble_info -- name = prefix_name (all_prefixes[i], priv.orig_sizeflag); -- if (name == NULL) -- name = INTERNAL_DISASSEMBLER_ERROR; --- (*info->fprintf_func) (info->stream, "%s", name); --- return 1; --- } --+ if ((extension = check_for_extensions(&priv))) { --+ strcpy(obuf, extension); --+ obufp = &obuf[strlen(obuf)]; --+ } else { --+ (*info->fprintf_func) (info->stream, "%s", name); --+ return 1; --+ } --+ } -- } -- -- /* Check if the REX prefix is used. */ --@@ -11637,7 +11667,7 @@ print_insn (bfd_vma pc, disassemble_info -- all_prefixes[last_data_prefix] = 0; -- -- prefix_length = 0; --- for (i = 0; i < (int) ARRAY_SIZE (all_prefixes); i++) --+ for (i = 0; !extension && i < (int) ARRAY_SIZE (all_prefixes); i++) -- if (all_prefixes[i]) -- { -- const char *name; --@@ -11655,7 +11685,8 @@ print_insn (bfd_vma pc, disassemble_info -- return MAX_CODE_LENGTH; -- } -- --- obufp = mnemonicendp; --+ if (!extension) --+ obufp = mnemonicendp; -- for (i = strlen (obuf) + prefix_length; i < 6; i++) -- oappend (" "); -- oappend (" "); ----- gdb-7.6/bfd/coff-i386.c.orig --+++ gdb-7.6/bfd/coff-i386.c --@@ -141,7 +141,7 @@ coff_i386_reloc (bfd *abfd, -- #define DOIT(x) \ -- x = ((x & ~howto->dst_mask) | (((x & howto->src_mask) + diff) & howto->dst_mask)) -- --- if (diff != 0) --+ if (diff != 0) -- { -- reloc_howto_type *howto = reloc_entry->howto; -- unsigned char *addr = (unsigned char *) data + reloc_entry->address; ----- gdb-7.6/bfd/coff-x86_64.c.orig --+++ gdb-7.6/bfd/coff-x86_64.c --@@ -139,7 +139,7 @@ coff_amd64_reloc (bfd *abfd, -- #define DOIT(x) \ -- x = ((x & ~howto->dst_mask) | (((x & howto->src_mask) + diff) & howto->dst_mask)) -- --- if (diff != 0) --+ if (diff != 0) -- { -- reloc_howto_type *howto = reloc_entry->howto; -- unsigned char *addr = (unsigned char *) data + reloc_entry->address; ----- gdb-7.6/opcodes/arm-dis.c.orig --+++ gdb-7.6/opcodes/arm-dis.c --@@ -2103,7 +2103,7 @@ print_insn_coprocessor (bfd_vma pc, -- -- /* Is ``imm'' a negative number? */ -- if (imm & 0x40) --- imm |= (-1 << 7); --+ imm -= 0x80; -- -- func (stream, "%d", imm); -- } --diff -up gdb-7.6/bfd/elf64-ppc.c.orig gdb-7.6/bfd/elf64-ppc.c ----- gdb-7.6/bfd/elf64-ppc.c.orig 2016-02-02 11:04:25.436527347 -0500 --+++ gdb-7.6/bfd/elf64-ppc.c 2016-02-02 11:11:51.926468454 -0500 --@@ -11743,7 +11743,7 @@ ppc64_elf_size_stubs (struct bfd_link_in -- stub_sec = stub_sec->next) -- if ((stub_sec->flags & SEC_LINKER_CREATED) == 0) -- stub_sec->size = ((stub_sec->size + (1 << htab->plt_stub_align) - 1) --- & (-1 << htab->plt_stub_align)); --+ & -(1 << htab->plt_stub_align)); -- -- for (stub_sec = htab->stub_bfd->sections; -- stub_sec != NULL; --@@ -12093,7 +12093,7 @@ ppc64_elf_build_stubs (bfd_boolean emit_ -- stub_sec = stub_sec->next) -- if ((stub_sec->flags & SEC_LINKER_CREATED) == 0) -- stub_sec->size = ((stub_sec->size + (1 << htab->plt_stub_align) - 1) --- & (-1 << htab->plt_stub_align)); --+ & -(1 << htab->plt_stub_align)); -- -- for (stub_sec = htab->stub_bfd->sections; -- stub_sec != NULL; ----- gdb-7.6/include/opcode/ppc.h.orig --+++ gdb-7.6/include/opcode/ppc.h --@@ -278,7 +278,7 @@ extern const unsigned int num_powerpc_op -- /* Use with the shift field of a struct powerpc_operand to indicate -- that BITM and SHIFT cannot be used to determine where the operand -- goes in the insn. */ ---#define PPC_OPSHIFT_INV (-1 << 31) --+#define PPC_OPSHIFT_INV (-1U << 31) -- -- /* Values defined for the flags field of a struct powerpc_operand. */ -- ----- gdb-7.6/opcodes/mips-dis.c.orig --+++ gdb-7.6/opcodes/mips-dis.c --@@ -245,18 +245,6 @@ static const char * const mips_cp0_names -- "c0_taglo", "c0_taghi", "c0_errorepc", "$31" -- }; -- ---static const struct mips_cp0sel_name mips_cp0sel_names_mipsr5900[] = ---{ --- { 24, 2, "c0_iab" }, --- { 24, 3, "c0_iabm" }, --- { 24, 4, "c0_dab" }, --- { 24, 5, "c0_dabm" }, --- { 24, 6, "c0_dvb" }, --- { 24, 7, "c0_dvbm" }, --- { 25, 1, "c0_perfcnt,1" }, --- { 25, 2, "c0_perfcnt,2" } ---}; --- -- static const char * const mips_cp0_names_mips3264[32] = -- { -- "c0_index", "c0_random", "c0_entrylo0", "c0_entrylo1", ----- gdb-7.6/gdb/ada-lang.c.orig --+++ gdb-7.6/gdb/ada-lang.c --@@ -10503,7 +10503,7 @@ ada_evaluate_subexp (struct type *expect -- } -- else -- arg1 = ada_value_struct_elt (arg1, &exp->elts[pc + 2].string, 0); --- arg1 = unwrap_value (arg1); --+ arg1 = unwrap_value (arg1); -- return ada_to_fixed_value (arg1); -- -- case OP_TYPE: ----- gdb-7.6/gdb/linux-record.c.orig --+++ gdb-7.6/gdb/linux-record.c --@@ -112,7 +112,7 @@ record_linux_sockaddr (struct regcache * -- "memory at addr = 0x%s len = %d.\n", -- phex_nz (len, tdep->size_pointer), -- tdep->size_int); --- return -1; --+ return -1; -- } -- addrlen = (int) extract_unsigned_integer (a, tdep->size_int, byte_order); -- if (addrlen <= 0 || addrlen > tdep->size_sockaddr) --@@ -150,7 +150,7 @@ record_linux_msghdr (struct regcache *re -- "len = %d.\n", -- phex_nz (addr, tdep->size_pointer), -- tdep->size_msghdr); --- return -1; --+ return -1; -- } -- -- /* msg_name msg_namelen */ --@@ -186,7 +186,7 @@ record_linux_msghdr (struct regcache *re -- "len = %d.\n", -- phex_nz (addr,tdep->size_pointer), -- tdep->size_iovec); --- return -1; --+ return -1; -- } -- tmpaddr = (CORE_ADDR) extract_unsigned_integer (iov, -- tdep->size_pointer, --@@ -948,7 +948,7 @@ Do you want to stop the program?"), -- "memory at addr = 0x%s len = %d.\n", -- OUTPUT_REG (tmpulongest, tdep->arg2), -- tdep->size_ulong); --- return -1; --+ return -1; -- } -- tmpulongest = extract_unsigned_integer (a, tdep->size_ulong, -- byte_order); ----- gdb-7.6/gdb/inflow.c.orig --+++ gdb-7.6/gdb/inflow.c --@@ -391,7 +391,7 @@ terminal_ours_1 (int output_only) -- if (tinfo->run_terminal != NULL || gdb_has_a_terminal () == 0) -- return; -- --- { --+ { -- #ifdef SIGTTOU -- /* Ignore this signal since it will happen when we try to set the -- pgrp. */ ----- gdb-7.6/gdb/printcmd.c.orig --+++ gdb-7.6/gdb/printcmd.c --@@ -1045,7 +1045,7 @@ print_command_2 (char *exp, int inspect, -- else -- val = access_value_history (0); -- --- printf_filtered ("%d %d %d %d %d %d\n", --+ printf_filtered ("%d %d %d %d %d %d\n", -- TYPE_CODE (check_typedef(value_type (val))), -- TYPE_UNSIGNED (check_typedef(value_type (val))), -- TYPE_LENGTH (check_typedef(value_type(val))), ----- gdb-7.6/gdb/c-typeprint.c.orig --+++ gdb-7.6/gdb/c-typeprint.c --@@ -1293,7 +1293,7 @@ c_type_print_base (struct type *type, st -- if (TYPE_NFIELDS (type) != 0 || TYPE_NFN_FIELDS (type) != 0) -- fprintf_filtered (stream, "\n"); -- --- for (i = 0; i < TYPE_TYPEDEF_FIELD_COUNT (type); i++) --+ for (i = 0; i < TYPE_TYPEDEF_FIELD_COUNT (type); i++) -- { -- struct type *target = TYPE_TYPEDEF_FIELD_TYPE (type, i); -- ----- gdb-7.6/gdb/symtab.c.orig --+++ gdb-7.6/gdb/symtab.c --@@ -5139,6 +5139,8 @@ static void get_user_print_option_addres -- extern int get_frame_offset(CORE_ADDR); -- static void gdb_set_crash_block(struct gnu_request *); -- void gdb_command_funnel(struct gnu_request *); --+static long lookup_struct_contents(struct gnu_request *); --+static void iterate_datatypes(struct gnu_request *); -- -- struct objfile *gdb_kernel_objfile = { 0 }; -- --@@ -5242,6 +5244,14 @@ gdb_command_funnel(struct gnu_request *r -- req->flags |= GNU_COMMAND_FAILED; -- break; -- --+ case GNU_LOOKUP_STRUCT_CONTENTS: --+ req->value = lookup_struct_contents(req); --+ break; --+ --+ case GNU_GET_NEXT_DATATYPE: --+ iterate_datatypes(req); --+ break; --+ -- default: -- req->flags |= GNU_COMMAND_FAILED; -- break; --@@ -5779,4 +5789,135 @@ gdb_get_crash_block(void) -- else -- return NULL; -- } --+ --+static long --+lookup_struct_contents(struct gnu_request *req) --+{ --+ int i; --+ long r; --+ struct field *f; --+ struct main_type *m; --+ const char *n; --+ struct main_type *top_m = (struct main_type *)req->addr; --+ char *type_name = req->type_name; --+ --+ if (!top_m || !type_name) --+ return 0; --+ --+ for (i = 0; i < top_m->nfields; i++) --+ { --+ f = top_m->flds_bnds.fields + i; --+ if (!f->type) --+ continue; --+ m = f->type->main_type; --+ --+ // If the field is an array, check the target type - --+ // it might be structure, or might not be. --+ // - struct request_sock *syn_table[0]; --+ // here m->target_type->main_type->code is expected --+ // to be TYPE_CODE_PTR --+ // - struct list_head vec[TVN_SIZE]; --+ // here m->target_type->main_type->code should be --+ // TYPE_CODE_STRUCT --+ if (m->code == TYPE_CODE_ARRAY && m->target_type) --+ m = m->target_type->main_type; --+ --+ /* Here is a recursion. --+ * If we have struct variable (not pointer), --+ * scan this inner structure --+ */ --+ if (m->code == TYPE_CODE_STRUCT) { --+ req->addr = (ulong)m; --+ r = lookup_struct_contents(req); --+ req->addr = (ulong)top_m; --+ if (r) --+ return 1; --+ } --+ --+ if (m->code == TYPE_CODE_PTR && m->target_type) --+ m = m->target_type->main_type; --+ if (m->name) --+ n = m->name; --+ else if (m->tag_name) --+ n = m->tag_name; --+ else --+ continue; --+ --+ if (strstr(n, type_name)) --+ return 1; --+ } --+ --+ return 0; --+} --+ --+static void --+iterate_datatypes (struct gnu_request *req) --+{ --+ static struct block_iterator bi; // Keeping this static will simplify code --+ struct block *b; --+ int do_return = 0; --+ struct global_iterator *gi = &req->global_iterator; --+ --+ if (gi->finished) --+ return; --+ --+ if (gi->obj == NULL) --+ { --+ gi->obj = current_program_space->objfiles; --+ gi->symtab = NULL; --+ do_return = 1; // The initial case - we don't need to make next step. --+ } --+ --+ for (; gi->obj; gi->obj = gi->obj->next, gi->symtab = NULL) --+ { --+ if (gi->symtab == NULL) --+ { --+ // Symtab `symtab` is nullified for every objfile --+ if (gi->obj->sf) --+ gi->obj->sf->qf->expand_all_symtabs(gi->obj); --+ gi->symtab = gi->obj->symtabs; --+ gi->sym = NULL; --+ } --+ --+ for (; gi->symtab; gi->symtab = gi->symtab->next, gi->block_index = -1) --+ { --+ if (!gi->symtab->primary) --+ continue; --+ --+ if (gi->block_index == -1) --+ { --+ gi->block_index = GLOBAL_BLOCK; --+ gi->sym = NULL; --+ } --+ for (; gi->block_index <= STATIC_BLOCK; gi->block_index++, gi->sym = NULL) --+ { --+ if (!gi->sym) --+ { --+ b = BLOCKVECTOR_BLOCK(BLOCKVECTOR(gi->symtab), gi->block_index); --+ gi->sym = block_iterator_first(b, &bi); --+ } --+ for (; gi->sym; gi->sym = block_iterator_next(&bi)) --+ { --+ QUIT; --+ --+ if (SYMBOL_CLASS (gi->sym) != LOC_TYPEDEF) --+ continue; --+ --+ // Iteration 1 (do_return == 0): initialization --+ // Iteration 2 (do_return == 1): iterate symbol --+ if (do_return++ == 0) --+ continue; --+ --+ // Yield the current symbol and its size --+ req->addr = (ulong)(gi->sym->type->main_type); --+ req->name = (char *)(gi->sym->ginfo.name); --+ req->length = gi->sym->type->length; --+ --+ return; --+ } --+ } --+ } --+ } --+ gi->finished = 1; --+} -- #endif ----- gdb-7.6/bfd/elf64-s390.c.orig --+++ gdb-7.6/bfd/elf64-s390.c --@@ -323,10 +323,10 @@ elf_s390_reloc_name_lookup (bfd *abfd AT -- && strcasecmp (elf_howto_table[i].name, r_name) == 0) -- return &elf_howto_table[i]; -- --- if (strcasecmp (elf64_s390_vtinherit_howto.name, r_name) == 0) --- return &elf64_s390_vtinherit_howto; --- if (strcasecmp (elf64_s390_vtentry_howto.name, r_name) == 0) --- return &elf64_s390_vtentry_howto; --+ if (strcasecmp (elf64_s390_vtinherit_howto.name, r_name) == 0) --+ return &elf64_s390_vtinherit_howto; --+ if (strcasecmp (elf64_s390_vtentry_howto.name, r_name) == 0) --+ return &elf64_s390_vtentry_howto; -- -- return NULL; -- } ----- gdb-7.6/gdb/symtab.c.orig --+++ gdb-7.6/gdb/symtab.c --@@ -5122,7 +5122,7 @@ When enabled, debugging messages are pri -- #define GDB_COMMON -- #include "../../defs.h" -- ---static void get_member_data(struct gnu_request *, struct type *); --+static void get_member_data(struct gnu_request *, struct type *, long, int); -- static void dump_enum(struct type *, struct gnu_request *); -- static void eval_enum(struct type *, struct gnu_request *); -- static void gdb_get_line_number(struct gnu_request *); --@@ -5327,7 +5327,7 @@ gdb_get_datatype(struct gnu_request *req -- req->typecode = TYPE_CODE(sym->type); -- req->length = TYPE_LENGTH(sym->type); -- if (req->member) --- get_member_data(req, sym->type); --+ get_member_data(req, sym->type, 0, 1); -- -- if (TYPE_CODE(sym->type) == TYPE_CODE_ENUM) { -- if (req->flags & GNU_PRINT_ENUMERATORS) --@@ -5397,7 +5397,7 @@ gdb_get_datatype(struct gnu_request *req -- } -- -- if (req->member) --- get_member_data(req, type); --+ get_member_data(req, type, 0, 1); -- -- break; -- --@@ -5480,7 +5480,7 @@ eval_enum(struct type *type, struct gnu_ -- * member field, and when found, return its relevant data. -- */ -- static void ---get_member_data(struct gnu_request *req, struct type *type) --+get_member_data(struct gnu_request *req, struct type *type, long offset, int is_first) -- { -- register short i; -- struct field *nextfield; --@@ -5492,7 +5492,7 @@ get_member_data(struct gnu_request *req, -- nfields = TYPE_MAIN_TYPE(type)->nfields; -- nextfield = TYPE_MAIN_TYPE(type)->flds_bnds.fields; -- --- if (nfields == 0) { --+ if (nfields == 0 && is_first /* The first call */) { -- struct type *newtype; -- newtype = lookup_transparent_type(req->name); -- if (newtype) { --@@ -5505,13 +5505,18 @@ get_member_data(struct gnu_request *req, -- -- for (i = 0; i < nfields; i++) { -- if (STREQ(req->member, nextfield->name)) { --- req->member_offset = nextfield->loc.bitpos; --+ req->member_offset = offset + nextfield->loc.bitpos; -- req->member_length = TYPE_LENGTH(nextfield->type); -- req->member_typecode = TYPE_CODE(nextfield->type); -- if ((req->member_typecode == TYPE_CODE_TYPEDEF) && -- (typedef_type = check_typedef(nextfield->type))) -- req->member_length = TYPE_LENGTH(typedef_type); -- return; --+ } else if (*nextfield->name == 0) { /* Anonymous struct/union */ --+ get_member_data(req, nextfield->type, --+ offset + nextfield->loc.bitpos, 0); --+ if (req->member_offset != -1) --+ return; -- } -- nextfield++; -- } --@@ -5706,7 +5711,7 @@ gdb_get_symbol_type(struct gnu_request * -- } -- -- if (req->member) --- get_member_data(req, type); --+ get_member_data(req, type, 0, 1); -- -- do_cleanups (old_chain); -- } --diff -up gdb-7.6/bfd/configure.orig gdb-7.6/bfd/configure ----- gdb-7.6/bfd/configure.orig 2017-02-17 17:19:51.654898822 -0500 --+++ gdb-7.6/bfd/configure 2017-02-17 17:19:57.922038757 -0500 --@@ -12193,7 +12193,7 @@ fi -- -- NO_WERROR= -- if test "${ERROR_ON_WARNING}" = yes ; then --- GCC_WARN_CFLAGS="$GCC_WARN_CFLAGS -Werror" --+ GCC_WARN_CFLAGS="$GCC_WARN_CFLAGS" -- NO_WERROR="-Wno-error" -- fi -- --diff -up gdb-7.6/opcodes/configure.orig gdb-7.6/opcodes/configure ----- gdb-7.6/opcodes/configure.orig 2017-02-17 17:19:08.849943016 -0500 --+++ gdb-7.6/opcodes/configure 2017-02-17 17:19:23.256264699 -0500 --@@ -11539,7 +11539,7 @@ fi -- -- NO_WERROR= -- if test "${ERROR_ON_WARNING}" = yes ; then --- GCC_WARN_CFLAGS="$GCC_WARN_CFLAGS -Werror" --+ GCC_WARN_CFLAGS="$GCC_WARN_CFLAGS" -- NO_WERROR="-Wno-error" -- fi -- ----- gdb-7.6/gdb/symtab.c.orig --+++ gdb-7.6/gdb/symtab.c --@@ -5266,6 +5266,7 @@ gdb_get_line_number(struct gnu_request * -- { -- struct symtab_and_line sal; -- struct symbol *sym; --+ struct objfile *objfile; -- CORE_ADDR pc; -- -- #define LASTCHAR(s) (s[strlen(s)-1]) --@@ -5281,8 +5282,22 @@ gdb_get_line_number(struct gnu_request * -- sal = find_pc_line(pc, 0); -- -- if (!sal.symtab) { --- req->buf[0] = '\0'; --- return; --+ /* --+ * If a module address line number can't be found, it's typically --+ * due to its addrmap still containing offset values because its --+ * objfile doesn't have full symbols loaded. --+ */ --+ if (req->lm) { --+ objfile = req->lm->loaded_objfile; --+ if (!objfile_has_full_symbols(objfile) && objfile->sf) { --+ objfile->sf->qf->expand_all_symtabs(objfile); --+ sal = find_pc_line(pc, 0); --+ } --+ } --+ if (!sal.symtab) { --+ req->buf[0] = '\0'; --+ return; --+ } -- } -- -- if (sal.symtab->filename && sal.symtab->dirname) { --@@ -5557,7 +5572,6 @@ struct load_module *gdb_current_load_mod -- static void -- gdb_add_symbol_file(struct gnu_request *req) -- { --- register struct objfile *loaded_objfile = NULL; -- register struct objfile *objfile; -- register struct minimal_symbol *m; -- struct load_module *lm; --@@ -5576,6 +5590,7 @@ gdb_add_symbol_file(struct gnu_request * -- -- req->name = lm->mod_namelist; -- gdb_delete_symbol_file(req); --+ lm->loaded_objfile = NULL; -- -- if ((lm->mod_flags & MOD_NOPATCH) == 0) { -- for (i = 0 ; i < lm->mod_sections; i++) { --@@ -5623,12 +5638,15 @@ gdb_add_symbol_file(struct gnu_request * -- -- ALL_OBJFILES(objfile) { -- if (same_file(objfile->name, lm->mod_namelist)) { --- loaded_objfile = objfile; --+ if (objfile->separate_debug_objfile) --+ lm->loaded_objfile = objfile->separate_debug_objfile; --+ else --+ lm->loaded_objfile = objfile; -- break; -- } -- } -- --- if (!loaded_objfile) --+ if (!lm->loaded_objfile) -- req->flags |= GNU_COMMAND_FAILED; -- } -- ----- gdb-7.6/gdb/symtab.c.orig --+++ gdb-7.6/gdb/symtab.c --@@ -5500,7 +5500,7 @@ get_member_data(struct gnu_request *req, -- register short i; -- struct field *nextfield; -- short nfields; --- struct type *typedef_type; --+ struct type *typedef_type, *target_type; -- -- req->member_offset = -1; -- --@@ -5523,6 +5523,13 @@ get_member_data(struct gnu_request *req, -- req->member_offset = offset + nextfield->loc.bitpos; -- req->member_length = TYPE_LENGTH(nextfield->type); -- req->member_typecode = TYPE_CODE(nextfield->type); --+ req->member_main_type_name = (char *)TYPE_NAME(nextfield->type); --+ req->member_main_type_tag_name = (char *)TYPE_TAG_NAME(nextfield->type); --+ target_type = TYPE_TARGET_TYPE(nextfield->type); --+ if (target_type) { --+ req->member_target_type_name = (char *)TYPE_NAME(target_type); --+ req->member_target_type_tag_name = (char *)TYPE_TAG_NAME(target_type); --+ } -- if ((req->member_typecode == TYPE_CODE_TYPEDEF) && -- (typedef_type = check_typedef(nextfield->type))) -- req->member_length = TYPE_LENGTH(typedef_type); -- ----- gdb-7.6/gdb/symtab.c.orig --+++ gdb-7.6/gdb/symtab.c --@@ -5727,6 +5727,7 @@ gdb_get_symbol_type(struct gnu_request * -- req->type_name = (char *)TYPE_MAIN_TYPE(type)->name; -- req->typecode = TYPE_MAIN_TYPE(type)->code; -- req->length = type->length; --+ req->type_tag_name = (char *)TYPE_TAG_NAME(type); -- target_type = TYPE_MAIN_TYPE(type)->target_type; -- -- if (target_type) { ----- gdb-7.6/gdb/common/linux-ptrace.c.orig --+++ gdb-7.6/gdb/common/linux-ptrace.c --@@ -108,14 +108,14 @@ linux_ptrace_test_ret_to_nx (void) -- ".globl linux_ptrace_test_ret_to_nx_instr;" -- "linux_ptrace_test_ret_to_nx_instr:" -- "ret" --- : : "r" (return_address) : "%esp", "memory"); --+ : : "r" (return_address) : "memory"); -- #elif defined __x86_64__ -- asm volatile ("pushq %0;" -- ".globl linux_ptrace_test_ret_to_nx_instr;" -- "linux_ptrace_test_ret_to_nx_instr:" -- "ret" -- : : "r" ((uint64_t) (uintptr_t) return_address) --- : "%rsp", "memory"); --+ : "memory"); -- #else -- # error "!__i386__ && !__x86_64__" -- #endif ----- gdb-7.6/gdb/features/aarch64.c.orig --+++ gdb-7.6/gdb/features/aarch64.c --@@ -5,7 +5,6 @@ -- #include "osabi.h" -- #include "target-descriptions.h" -- ---struct target_desc *tdesc_aarch64; -- static void -- initialize_tdesc_aarch64 (void) -- { ----- gdb-7.6/gdb/aarch64-linux-nat.c.orig --+++ gdb-7.6/gdb/aarch64-linux-nat.c --@@ -37,6 +37,7 @@ -- -- #include "gregset.h" -- --+extern struct target_desc *tdesc_aarch64; -- #include "features/aarch64.c" -- -- /* Defines ps_err_e, struct ps_prochandle. */ ----- gdb-7.6/gdb/aarch64-tdep.c.orig --+++ gdb-7.6/gdb/aarch64-tdep.c --@@ -52,6 +52,7 @@ -- #include "gdb_assert.h" -- #include "vec.h" -- --+struct target_desc *tdesc_aarch64; -- #include "features/aarch64.c" -- #include "features/aarch64-without-fpu.c" -- ----- gdb-7.6/gdb/symtab.c.orig --+++ gdb-7.6/gdb/symtab.c --@@ -2080,7 +2080,7 @@ find_pc_sect_symtab (CORE_ADDR pc, struct obj_section *section) -- struct symtab *s = NULL; -- struct symtab *best_s = NULL; -- struct objfile *objfile; --- CORE_ADDR distance = 0; --+ CORE_ADDR distance = 0, start, end; -- struct minimal_symbol *msymbol; -- -- /* If we know that this is not a text address, return failure. This is --@@ -2117,10 +2117,20 @@ find_pc_sect_symtab (CORE_ADDR pc, struct obj_section *section) -- bv = BLOCKVECTOR (s); -- b = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK); -- --- if (BLOCK_START (b) <= pc --- && BLOCK_END (b) > pc --- && (distance == 0 --- || BLOCK_END (b) - BLOCK_START (b) < distance)) --+ start = BLOCK_START (b); --+ end = BLOCK_END (b); --+ --+ /* --+ * If we have an addrmap mapping code addresses to blocks, and pc --+ * is in the range [start, end), let's use it. --+ */ --+ if ((pc >= start && pc < end) && BLOCKVECTOR_MAP (bv)) { --+ if (addrmap_find (BLOCKVECTOR_MAP (bv), pc)) --+ return s; --+ } --+ --+ if ((pc >= start && pc < end) && ((distance == 0) --+ || (end - start < distance))) -- { -- /* For an objfile that has its functions reordered, -- find_pc_psymtab will find the proper partial symbol table ----- gdb-7.6/gdb/mips-tdep.c.orig --+++ gdb-7.6/gdb/mips-tdep.c --@@ -3261,6 +3261,16 @@ restart: -- /* Irix 6.2 N32 ABI uses sd instructions for saving $gp and $ra. */ -- set_reg_offset (gdbarch, this_cache, reg, sp + low_word); -- } --+ else if (((inst & 0xFFE08020) == 0xeba00020) /* gssq reg,reg,offset($sp) */ --+ && regsize_is_64_bits) --+ { --+ reg = (inst >> 16) & 0x1F; --+ low_word = ((((inst >> 6) & 0x1FF) ^ 0x100) - 0x100) << 4; --+ set_reg_offset (gdbarch, this_cache, reg, sp + low_word); --+ reg = inst & 0x1F; --+ low_word = (((((inst >> 6) & 0x1FF) ^ 0x100) - 0x100) << 4) + 8; --+ set_reg_offset (gdbarch, this_cache, reg, sp + low_word); --+ } -- else if (high_word == 0x27be) /* addiu $30,$sp,size */ -- { -- /* Old gcc frame, r30 is virtual frame pointer. */ -diff --git a/gdb-7.6-ppc64le-support.patch b/gdb-8.1-ppc64le-support.patch -similarity index 100% -rename from gdb-7.6-ppc64le-support.patch -rename to gdb-8.1-ppc64le-support.patch -diff --git a/gdb-8.1.patch b/gdb-8.1.patch -new file mode 100644 -index 0000000..5dcd589 ---- /dev/null -+++ b/gdb-8.1.patch -@@ -0,0 +1,1615 @@ -+diff -aurp gdb-8.1.orig/gdb/cli/cli-cmds.c gdb-8.1/gdb/cli/cli-cmds.c -+--- gdb-8.1.orig/gdb/cli/cli-cmds.c 2021-06-04 09:43:28.953373700 +0800 -++++ gdb-8.1/gdb/cli/cli-cmds.c 2021-06-04 10:49:01.528989433 +0800 -+@@ -306,6 +306,11 @@ complete_command (const char *arg, int f -+ } -+ } -+ -++#ifdef CRASH_MERGE -++static int crash_from_tty = 0; -++extern "C" void untrusted_file(FILE *, char *); -++#endif -++ -+ int -+ is_complete_command (struct cmd_list_element *c) -+ { -+@@ -521,8 +526,31 @@ find_and_open_script (const char *script -+ close (fd); -+ errno = save_errno; -+ } -+- else -+- opened.emplace (gdb_file_up (result), std::move (full_path)); -++#ifdef CRASH_MERGE -++ /* -++ * Only allow trusted versions of .gdbinit files to be -++ * sourced during session initialization. -++ */ -++ if (crash_from_tty == -1) -++ { -++ struct stat statbuf; -++ FILE *stream = result; -++ int _fd = fileno (stream); -++ if (fstat (_fd, &statbuf) < 0) -++ { -++ perror_with_name (full_path.get()); -++ fclose (stream); -++ return opened; -++ } -++ if (statbuf.st_uid != getuid () || (statbuf.st_mode & S_IWOTH)) -++ { -++ untrusted_file(NULL, full_path.get()); -++ fclose (stream); -++ return opened; -++ } -++ } -++#endif -++ opened.emplace (gdb_file_up (result), std::move (full_path)); -+ -+ return opened; -+ } -+@@ -586,7 +614,11 @@ source_script_with_search (const char *f -+ If the source command was invoked interactively, throw an -+ error. Otherwise (e.g. if it was invoked by a script), -+ just emit a warning, rather than cause an error. */ -++#ifdef CRASH_MERGE -++ if (from_tty > 0) -++#else -+ if (from_tty) -++#endif -+ perror_with_name (file); -+ else -+ { -+@@ -610,7 +642,13 @@ source_script_with_search (const char *f -+ void -+ source_script (const char *file, int from_tty) -+ { -++#ifdef CRASH_MERGE -++ crash_from_tty = from_tty; -++#endif -+ source_script_with_search (file, from_tty, 0); -++#ifdef CRASH_MERGE -++ crash_from_tty = 0; -++#endif -+ } -+ -+ static void -+diff -aurp gdb-8.1.orig/gdb/defs.h gdb-8.1/gdb/defs.h -+--- gdb-8.1.orig/gdb/defs.h 2021-06-04 09:43:28.445371961 +0800 -++++ gdb-8.1/gdb/defs.h 2021-06-04 10:49:01.532989433 +0800 -+@@ -665,4 +665,7 @@ DEF_ENUM_FLAGS_TYPE (enum user_selected_ -+ -+ #include "utils.h" -+ -++#ifdef CRASH_MERGE -++extern "C" int gdb_main_entry(int, char **); -++#endif -+ #endif /* #ifndef DEFS_H */ -+diff -aurp gdb-8.1.orig/gdb/dwarf2read.c gdb-8.1/gdb/dwarf2read.c -+--- gdb-8.1.orig/gdb/dwarf2read.c 2021-06-04 09:43:28.505372166 +0800 -++++ gdb-8.1/gdb/dwarf2read.c 2021-06-04 10:49:01.532989433 +0800 -+@@ -3449,7 +3449,11 @@ read_gdb_index_from_section (struct objf -+ indices. */ -+ if (version < 4) -+ { -++#ifdef CRASH_MERGE -++ static int warning_printed = 1; -++#else -+ static int warning_printed = 0; -++#endif -+ if (!warning_printed) -+ { -+ warning (_("Skipping obsolete .gdb_index section in %s."), -+@@ -3468,7 +3472,11 @@ read_gdb_index_from_section (struct objf -+ "set use-deprecated-index-sections on". */ -+ if (version < 6 && !deprecated_ok) -+ { -++#ifdef CRASH_MERGE -++ static int warning_printed = 1; -++#else -+ static int warning_printed = 0; -++#endif -+ if (!warning_printed) -+ { -+ warning (_("\ -+diff -aurp gdb-8.1.orig/gdb/main.c gdb-8.1/gdb/main.c -+--- gdb-8.1.orig/gdb/main.c 2021-06-04 09:43:28.537372276 +0800 -++++ gdb-8.1/gdb/main.c 2021-06-04 10:49:01.532989433 +0800 -+@@ -306,6 +306,14 @@ setup_alternate_signal_stack (void) -+ #endif -+ } -+ -++#ifdef CRASH_MERGE -++extern "C" void update_gdb_hooks(void); -++extern "C" void main_loop(void); -++extern "C" unsigned long crash_get_kaslr_offset(void); -++extern "C" int console(const char *, ...); -++void crash_target_init (void); -++#endif -++ -+ /* Call command_loop. */ -+ -+ /* Prevent inlining this function for the benefit of GDB's selftests -+@@ -849,7 +857,11 @@ captured_main_1 (struct captured_main_ar -+ quiet = 1; -+ } -+ -++#ifdef CRASH_MERGE -++ save_original_signals_state (1); -++#else -+ save_original_signals_state (quiet); -++#endif -+ -+ /* Try to set up an alternate signal stack for SIGSEGV handlers. */ -+ setup_alternate_signal_stack (); -+@@ -920,7 +932,7 @@ captured_main_1 (struct captured_main_ar -+ { -+ print_gdb_version (gdb_stdout, false); -+ wrap_here (""); -+- printf_filtered ("\n"); -++ printf_filtered ("\n\n"); -+ exit (0); -+ } -+ -+@@ -960,6 +972,10 @@ captured_main_1 (struct captured_main_ar -+ look at things by now. Initialize the default interpreter. */ -+ set_top_level_interpreter (interpreter_p); -+ -++#ifdef CRASH_MERGE -++ update_gdb_hooks(); -++#endif -++ -+ /* FIXME: cagney/2003-02-03: The big hack (part 2 of 2) that lets -+ GDB retain the old MI1 interpreter startup behavior. Output the -+ copyright message after the interpreter is installed when it is -+@@ -986,15 +1002,22 @@ captured_main_1 (struct captured_main_ar -+ processed; it sets global parameters, which are independent of -+ what file you are debugging or what directory you are in. */ -+ if (system_gdbinit && !inhibit_gdbinit) -++#ifdef CRASH_MERGE -++ catch_command_errors (source_script, system_gdbinit, -1); -++#else -+ catch_command_errors (source_script, system_gdbinit, 0); -+- -++#endif -+ /* Read and execute $HOME/.gdbinit file, if it exists. This is done -+ *before* all the command line arguments are processed; it sets -+ global parameters, which are independent of what file you are -+ debugging or what directory you are in. */ -+ -+ if (home_gdbinit && !inhibit_gdbinit && !inhibit_home_gdbinit) -++#ifdef CRASH_MERGE -++ catch_command_errors (source_script, home_gdbinit, -1); -++#else -+ catch_command_errors (source_script, home_gdbinit, 0); -++#endif -+ -+ /* Process '-ix' and '-iex' options early. */ -+ for (i = 0; i < cmdarg_vec.size (); i++) -+@@ -1039,7 +1062,11 @@ captured_main_1 (struct captured_main_ar -+ if (catch_command_errors (exec_file_attach, execarg, -+ !batch_flag)) -+ catch_command_errors (symbol_file_add_main_adapter, symarg, -++#ifdef CRASH_MERGE -++ 0); -++#else -+ !batch_flag); -++#endif -+ } -+ else -+ { -+@@ -1098,7 +1125,11 @@ captured_main_1 (struct captured_main_ar -+ { -+ auto_load_local_gdbinit_loaded = 1; -+ -+- catch_command_errors (source_script, local_gdbinit, 0); -++#ifdef CRASH_MERGE -++ catch_command_errors (source_script, local_gdbinit, -1); -++#else -++ catch_command_errors (source_script, local_gdbinit, 0); -++#endif -+ } -+ } -+ -+@@ -1146,6 +1177,16 @@ captured_main (void *data) -+ -+ captured_main_1 (context); -+ -++#ifdef CRASH_MERGE -++ /* Relocate the vmlinux. */ -++ objfile_rebase (symfile_objfile, crash_get_kaslr_offset()); -++ -++ crash_target_init(); -++ -++ /* Back to crash. */ -++ main_loop(); -++#endif -++ -+ /* NOTE: cagney/1999-11-07: There is probably no reason for not -+ moving this loop and the code found in captured_command_loop() -+ into the command_loop() proper. The main thing holding back that -+@@ -1161,6 +1202,9 @@ captured_main (void *data) -+ exception_print (gdb_stderr, ex); -+ } -+ END_CATCH -++#ifdef CRASH_MERGE -++ console("\n"); -++#endif -+ } -+ /* No exit -- exit is through quit_command. */ -+ } -+@@ -1183,6 +1227,22 @@ gdb_main (struct captured_main_args *arg -+ return 1; -+ } -+ -++#ifdef CRASH_MERGE -++/* -++ * NOTE: adapted from gdb.c, which is no longer built in; changed name of -++ * original main() to gdb_main_entry() for use as crash entry point -++ */ -++int -++gdb_main_entry (int argc, char **argv) -++{ -++ struct captured_main_args args; -++ memset (&args, 0, sizeof args); -++ args.argc = argc; -++ args.argv = argv; -++ args.interpreter_p = INTERP_CONSOLE; -++ return gdb_main (&args); -++} -++#endif -+ -+ /* Don't use *_filtered for printing help. We don't want to prompt -+ for continue no matter how small the screen or how much we're going -+diff -aurp gdb-8.1.orig/gdb/Makefile.in gdb-8.1/gdb/Makefile.in -+--- gdb-8.1.orig/gdb/Makefile.in 2021-06-04 09:43:28.529372249 +0800 -++++ gdb-8.1/gdb/Makefile.in 2021-06-04 10:49:01.532989433 +0800 -+@@ -542,7 +542,7 @@ CONFIG_DEP_SUBDIR = $(addsuffix /$(DEPDI -+ # It is also possible that you will need to add -I/usr/include/sys if -+ # your system doesn't have fcntl.h in /usr/include (which is where it -+ # should be according to Posix). -+-DEFS = @DEFS@ -++DEFS = -DCRASH_MERGE @DEFS@ -+ GDB_CFLAGS = -I. -I$(srcdir) -I$(srcdir)/common -I$(srcdir)/config \ -+ -DLOCALEDIR="\"$(localedir)\"" $(DEFS) -+ -+@@ -1110,6 +1110,7 @@ COMMON_SFILES = \ -+ symmisc.c \ -+ symtab.c \ -+ target.c \ -++ ../../crash_target.c \ -+ target-dcache.c \ -+ target-descriptions.c \ -+ target-memory.c \ -+@@ -1571,7 +1572,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $ -+ -+ TSOBS = inflow.o -+ -+-SUBDIRS = doc @subdirs@ data-directory $(GNULIB_BUILDDIR) -++SUBDIRS = build_no_subdirs -+ CLEANDIRS = $(SUBDIRS) -+ -+ # List of subdirectories in the build tree that must exist. -+@@ -1614,8 +1615,8 @@ generated_files = \ -+ # Flags needed to compile Python code -+ PYTHON_CFLAGS = @PYTHON_CFLAGS@ -+ -+-all: gdb$(EXEEXT) $(CONFIG_ALL) -+- @$(MAKE) $(FLAGS_TO_PASS) DO=all "DODIRS=`echo $(SUBDIRS) | sed 's/testsuite//'`" subdir_do -++all: gdb$(EXEEXT) -++ @$(MAKE) -s $(FLAGS_TO_PASS) DO=all "DODIRS=`echo $(SUBDIRS) | sed 's/testsuite//'`" subdir_do -+ -+ # Rule for compiling .c files in the top-level gdb directory. -+ # The order-only dependencies ensure that we create the build subdirectories. -+@@ -1920,14 +1921,15 @@ libgdb.a: $(LIBGDB_OBS) -+ # Removing the old gdb first works better if it is running, at least on SunOS. -+ gdb$(EXEEXT): gdb.o $(LIBGDB_OBS) $(ADD_DEPS) $(CDEPS) $(TDEPLIBS) -+ $(SILENCE) rm -f gdb$(EXEEXT) -++ @(cd ../..; make --no-print-directory GDB_FLAGS=-DGDB_8_1 library) -+ $(ECHO_CXXLD) $(CC_LD) $(INTERNAL_LDFLAGS) $(WIN32LDAPP) \ -+- -o gdb$(EXEEXT) gdb.o $(LIBGDB_OBS) \ -+- $(TDEPLIBS) $(TUI_LIBRARY) $(CLIBS) $(LOADLIBES) -++ -o $(shell /bin/cat mergeobj) $(LIBGDB_OBS) \ -++ $(TDEPLIBS) $(TUI_LIBRARY) $(CLIBS) $(LOADLIBES) $(shell /bin/cat mergelibs) -+ -+ # Convenience rule to handle recursion. -+ $(LIBGNU) $(GNULIB_H): all-lib -+ all-lib: $(GNULIB_BUILDDIR)/Makefile -+- @$(MAKE) $(FLAGS_TO_PASS) DO=all DODIRS=$(GNULIB_BUILDDIR) subdir_do -++ @$(MAKE) $(FLAGS_TO_PASS) DO=all DODIRS=$(GNULIB_BUILDDIR) subdir_do -s -+ .PHONY: all-lib -+ -+ # Convenience rule to handle recursion. -+@@ -2626,9 +2628,9 @@ ifeq ($(DEPMODE),depmode=gcc3) -+ # into place if the compile succeeds. We need this because gcc does -+ # not atomically write the dependency output file. -+ override COMPILE.post = -c -o $@ -MT $@ -MMD -MP \ -+- -MF $(@D)/$(DEPDIR)/$(basename $(@F)).Tpo -+-override POSTCOMPILE = @mv $(@D)/$(DEPDIR)/$(basename $(@F)).Tpo \ -+- $(@D)/$(DEPDIR)/$(basename $(@F)).Po -++ -MF $(subst ../..,.,$(@D))/$(DEPDIR)/$(basename $(@F)).Tpo -++override POSTCOMPILE = @mv $(subst ../..,.,$(@D))/$(DEPDIR)/$(basename $(@F)).Tpo \ -++ $(subst ../..,.,$(@D))/$(DEPDIR)/$(basename $(@F)).Po -+ else -+ override COMPILE.pre = source='$<' object='$@' libtool=no \ -+ DEPDIR=$(DEPDIR) $(DEPMODE) $(depcomp) \ -+diff -aurp gdb-8.1.orig/gdb/objfiles.h gdb-8.1/gdb/objfiles.h -+--- gdb-8.1.orig/gdb/objfiles.h 2021-06-04 09:43:28.477372071 +0800 -++++ gdb-8.1/gdb/objfiles.h 2021-06-04 10:49:01.536989434 +0800 -+@@ -502,9 +502,9 @@ extern int objfile_has_full_symbols (str -+ -+ extern int objfile_has_symbols (struct objfile *objfile); -+ -+-extern int have_partial_symbols (void); -++extern "C" int have_partial_symbols (void); -+ -+-extern int have_full_symbols (void); -++extern "C" int have_full_symbols (void); -+ -+ extern void objfile_set_sym_fns (struct objfile *objfile, -+ const struct sym_fns *sf); -+diff -aurp gdb-8.1.orig/gdb/printcmd.c gdb-8.1/gdb/printcmd.c -+--- gdb-8.1.orig/gdb/printcmd.c 2021-06-04 09:43:28.541372290 +0800 -++++ gdb-8.1/gdb/printcmd.c 2021-06-04 10:49:01.536989434 +0800 -+@@ -515,6 +515,10 @@ set_next_address (struct gdbarch *gdbarc -+ settings of the demangle and asm_demangle variables. Returns -+ non-zero if anything was printed; zero otherwise. */ -+ -++#ifdef CRASH_MERGE -++extern "C" int gdb_print_callback(unsigned long); -++#endif -++ -+ int -+ print_address_symbolic (struct gdbarch *gdbarch, CORE_ADDR addr, -+ struct ui_file *stream, -+@@ -525,6 +529,12 @@ print_address_symbolic (struct gdbarch * -+ int offset = 0; -+ int line = 0; -+ -++#ifdef CRASH_MERGE -++ if (!gdb_print_callback(addr)) { -++ return 0; -++ } -++#endif -++ -+ if (build_address_symbolic (gdbarch, addr, do_demangle, &name, &offset, -+ &filename, &line, &unmapped)) -+ return 0; -+@@ -1194,11 +1204,43 @@ print_command_1 (const char *exp, int vo -+ } -+ -+ static void -++print_command_2 (const char *exp, int voidprint) -++{ -++ struct value *val; -++ struct format_data fmt; -++ -++ print_command_parse_format (&exp, "print", &fmt); -++ -++ if (exp && *exp) -++ { -++ expression_up expr = parse_expression (exp); -++ val = evaluate_expression (expr.get ()); -++ } -++ else -++ { -++ val = access_value_history (0); -++ } -++ -++ printf_filtered ("%d %d %d %ld %ld %ld\n", -++ TYPE_CODE (check_typedef(value_type (val))), -++ TYPE_UNSIGNED (check_typedef(value_type (val))), -++ TYPE_LENGTH (check_typedef(value_type(val))), -++ value_offset (val), value_bitpos (val), value_bitsize(val)); -++ -++} -++ -++static void -+ print_command (const char *exp, int from_tty) -+ { -+ print_command_1 (exp, 1); -+ } -+ -++static void -++printm_command (const char *exp, int from_tty) -++{ -++ print_command_2 (exp, 1); -++} -++ -+ /* Same as print, except it doesn't print void results. */ -+ static void -+ call_command (const char *exp, int from_tty) -+@@ -2742,6 +2784,12 @@ EXP may be preceded with /FMT, where FMT -+ but no count or size letter (see \"x\" command).")); -+ set_cmd_completer (c, expression_completer); -+ add_com_alias ("p", "print", class_vars, 1); -++ -++ c = add_com ("printm", class_vars, printm_command, _("\ -++Similar to \"print\" command, but it used to print the type, size, offset,\n\ -++bitpos and bitsize of the expression EXP.")); -++ set_cmd_completer (c, expression_completer); -++ -+ add_com_alias ("inspect", "print", class_vars, 1); -+ -+ add_setshow_uinteger_cmd ("max-symbolic-offset", no_class, -+diff -aurp gdb-8.1.orig/gdb/psymtab.c gdb-8.1/gdb/psymtab.c -+--- gdb-8.1.orig/gdb/psymtab.c 2021-06-04 09:43:28.545372303 +0800 -++++ gdb-8.1/gdb/psymtab.c 2021-06-04 10:49:01.536989434 +0800 -+@@ -300,6 +300,10 @@ find_pc_sect_psymtab_closer (struct objf -+ return best_pst; -+ } -+ -++#ifdef CRASH_MERGE -++ extern "C" int gdb_line_number_callback(unsigned long, unsigned long, unsigned long); -++#endif -++ -+ /* Find which partial symtab contains PC and SECTION. Return NULL if -+ none. We return the psymtab that contains a symbol whose address -+ exactly matches PC, or, if we cannot find an exact match, the -+@@ -368,7 +372,13 @@ find_pc_sect_psymtab (struct objfile *ob -+ -+ best_pst = find_pc_sect_psymtab_closer (objfile, pc, section, pst, -+ msymbol); -++ -++#ifdef CRASH_MERGE -++ if ((best_pst != NULL) && -++ gdb_line_number_callback(pc, pst->textlow, pst->texthigh)) -++#else -+ if (best_pst != NULL) -++#endif -+ return best_pst; -+ } -+ -+diff -aurp gdb-8.1.orig/gdb/regcache.c gdb-8.1/gdb/regcache.c -+--- gdb-8.1.orig/gdb/regcache.c 2021-06-04 09:43:28.473372057 +0800 -++++ gdb-8.1/gdb/regcache.c 2021-06-04 10:49:01.548989434 +0800 -+@@ -1221,7 +1221,7 @@ regcache_read_pc (struct regcache *regca -+ if (regcache_cooked_read_unsigned (regcache, -+ gdbarch_pc_regnum (gdbarch), -+ &raw_val) == REG_UNAVAILABLE) -+- throw_error (NOT_AVAILABLE_ERROR, _("PC register is not available")); -++ //throw_error (NOT_AVAILABLE_ERROR, _("PC register is not available")); -+ -+ pc_val = gdbarch_addr_bits_remove (gdbarch, raw_val); -+ } -+diff -aurp gdb-8.1.orig/gdb/remote-sim.c gdb-8.1/gdb/remote-sim.c -+--- gdb-8.1.orig/gdb/remote-sim.c 2021-06-04 09:43:28.541372290 +0800 -++++ gdb-8.1/gdb/remote-sim.c 2021-06-04 10:49:01.536989434 +0800 -+@@ -1195,7 +1195,7 @@ gdbsim_target::mourn_inferior () -+ -+ remove_breakpoints (); -+ generic_mourn_inferior (); -+- delete_thread_silent (sim_data->remote_sim_ptid); -++ //delete_thread_silent (sim_data->remote_sim_ptid); -+ } -+ -+ /* Pass the command argument through to the simulator verbatim. The -+diff -aurp gdb-8.1.orig/gdb/symfile.c gdb-8.1/gdb/symfile.c -+--- gdb-8.1.orig/gdb/symfile.c 2021-06-04 09:43:28.549372317 +0800 -++++ gdb-8.1/gdb/symfile.c 2021-06-04 10:49:01.540989434 +0800 -+@@ -662,7 +662,8 @@ default_symfile_offsets (struct objfile -+ for (cur_sec = abfd->sections; cur_sec != NULL; cur_sec = cur_sec->next) -+ /* We do not expect this to happen; just skip this step if the -+ relocatable file has a section with an assigned VMA. */ -+- if (bfd_section_vma (abfd, cur_sec) != 0) -++ if (bfd_section_vma (abfd, cur_sec) != 0 -++ && strncmp (bfd_section_name (abfd, cur_sec), "__k", 3) != 0) -+ break; -+ -+ if (cur_sec == NULL) -+@@ -1096,6 +1097,13 @@ symbol_file_add_with_addrs (bfd *abfd, c -+ flags |= OBJF_MAINLINE; -+ objfile = new struct objfile (abfd, name, flags); -+ -++#ifdef CRASH_MERGE -++ if (add_flags & SYMFILE_MAINLINE) { -++ extern struct objfile *gdb_kernel_objfile; -++ gdb_kernel_objfile = objfile; -++ } -++#endif -++ -+ if (parent) -+ add_separate_debug_objfile (objfile, parent); -+ -+@@ -1364,6 +1372,11 @@ show_debug_file_directory (struct ui_fil -+ #define DEBUG_SUBDIRECTORY ".debug" -+ #endif -+ -++#ifdef CRASH_MERGE -++extern "C" int check_specified_module_tree(const char *, const char *); -++extern "C" char *check_specified_kernel_debug_file(); -++#endif -++ -+ /* Find a separate debuginfo file for OBJFILE, using DIR as the directory -+ where the original file resides (may not be the same as -+ dirname(objfile->name) due to symlinks), and DEBUGLINK as the file we are -+@@ -1389,6 +1402,15 @@ find_separate_debug_file (const char *di -+ if (separate_debug_file_exists (debugfile, crc32, objfile)) -+ return debugfile; -+ -++#ifdef CRASH_MERGE -++{ -++ if (check_specified_module_tree(objfile_name (objfile), debugfile.c_str()) && -++ separate_debug_file_exists(debugfile, crc32, objfile)) { -++ return debugfile; -++ } -++} -++#endif -++ -+ /* Then try in the subdirectory named DEBUG_SUBDIRECTORY. */ -+ debugfile = dir; -+ debugfile += DEBUG_SUBDIRECTORY; -+@@ -1509,6 +1531,13 @@ find_separate_debug_file_by_debuglink (s -+ } -+ } -+ -++#ifdef CRASH_MERGE -++ if (debugfile.empty ()) { -++ char *name_copy; -++ name_copy = check_specified_kernel_debug_file(); -++ return std::string (name_copy); -++ } -++#endif -+ return debugfile; -+ } -+ -+@@ -2188,8 +2217,10 @@ add_symbol_file_command (const char *arg -+ so we can't determine what section names are valid. */ -+ } -+ -++#ifndef CRASH_MERGE -+ if (from_tty && (!query ("%s", ""))) -+ error (_("Not confirmed.")); -++#endif -+ -+ objf = symbol_file_add (filename.get (), add_flags, §ion_addrs, -+ flags); -+@@ -3522,6 +3553,15 @@ bfd_byte * -+ symfile_relocate_debug_section (struct objfile *objfile, -+ asection *sectp, bfd_byte *buf) -+ { -++#ifdef CRASH_MERGE -++ /* Executable files have all the relocations already resolved. -++ * Handle files linked with --emit-relocs. -++ * http://sources.redhat.com/ml/gdb/2006-08/msg00137.html -++ */ -++ bfd *abfd = objfile->obfd; -++ if ((abfd->flags & EXEC_P) != 0) -++ return NULL; -++#endif -+ gdb_assert (objfile->sf->sym_relocate); -+ -+ return (*objfile->sf->sym_relocate) (objfile, sectp, buf); -+diff -aurp gdb-8.1.orig/gdb/symtab.c gdb-8.1/gdb/symtab.c -+--- gdb-8.1.orig/gdb/symtab.c 2021-06-04 09:43:28.525372235 +0800 -++++ gdb-8.1/gdb/symtab.c 2021-06-04 10:49:01.540989434 +0800 -+@@ -1874,27 +1874,44 @@ search_name_hash (enum language language -+ variable and thus can probably assume it will never hit the C++ -+ code). */ -+ -++#ifdef CRASH_MERGE -++static void gdb_bait_and_switch(char *, struct symbol *); -++#endif -+ struct block_symbol -+ lookup_symbol_in_language (const char *name, const struct block *block, -+ const domain_enum domain, enum language lang, -+ struct field_of_this_result *is_a_field_of_this) -+ { -++ struct block_symbol result; -+ demangle_result_storage storage; -+ const char *modified_name = demangle_for_lookup (name, lang, storage); -+ -+- return lookup_symbol_aux (modified_name, -++ result = lookup_symbol_aux (modified_name, -+ symbol_name_match_type::FULL, -+ block, domain, lang, -+ is_a_field_of_this); -++#ifdef CRASH_MERGE -++ if (result.symbol && (domain == VAR_DOMAIN)) -++ gdb_bait_and_switch((char *)modified_name, result.symbol); -++#endif -++ return result; -+ } -+ -+ /* See symtab.h. */ -+ -++#ifdef CRASH_MERGE -++static const struct block *gdb_get_crash_block(void); -++#endif -++ -+ struct block_symbol -+ lookup_symbol (const char *name, const struct block *block, -+ domain_enum domain, -+ struct field_of_this_result *is_a_field_of_this) -+ { -++#ifdef CRASH_MERGE -++ if (!block) -++ block = gdb_get_crash_block(); -++#endif -+ return lookup_symbol_in_language (name, block, domain, -+ current_language->la_language, -+ is_a_field_of_this); -+@@ -5978,3 +5995,814 @@ If zero then the symbol cache is disable -+ gdb::observers::new_objfile.attach (symtab_new_objfile_observer); -+ gdb::observers::free_objfile.attach (symtab_free_objfile_observer); -+ } -++ -++#ifdef CRASH_MERGE -++#include "gdb-stabs.h" -++#include "version.h" -++#define GDB_COMMON -++#include "../../defs.h" -++ -++static void get_member_data(struct gnu_request *, struct type *, long, int); -++static void dump_enum(struct type *, struct gnu_request *); -++static void eval_enum(struct type *, struct gnu_request *); -++static void gdb_get_line_number(struct gnu_request *); -++static void gdb_get_datatype(struct gnu_request *); -++static void gdb_get_symbol_type(struct gnu_request *); -++static void gdb_command_exists(struct gnu_request *); -++static void gdb_debug_command(struct gnu_request *); -++static void gdb_function_numargs(struct gnu_request *); -++static void gdb_add_symbol_file(struct gnu_request *); -++static void gdb_delete_symbol_file(struct gnu_request *); -++static void gdb_patch_symbol_values(struct gnu_request *); -++static void get_user_print_option_address(struct gnu_request *); -++extern int get_frame_offset(CORE_ADDR); -++static void gdb_set_crash_block(struct gnu_request *); -++extern "C" void gdb_command_funnel(struct gnu_request *); -++void gdb_command_funnel_1(struct gnu_request *); -++static long lookup_struct_contents(struct gnu_request *); -++static void iterate_datatypes(struct gnu_request *); -++ -++struct objfile *gdb_kernel_objfile = { 0 }; -++ -++static ulong gdb_merge_flags = 0; -++#define KERNEL_SYMBOLS_PATCHED (0x1) -++ -++#undef STREQ -++#define STREQ(A, B) (A && B && (strcmp(A, B) == 0)) -++//#define TYPE_CODE(t) (t->code ()) -++#define TYPE_TAG_NAME(t) (TYPE_MAIN_TYPE(t)->name) -++//#define TYPE_NFIELDS(t) (t->num_fields ()) -++//#define TYPE_NAME(t) (t->name ()) -++ -++/* -++ * All commands from above come through here. -++ */ -++void -++gdb_command_funnel(struct gnu_request *req) -++{ -++ try { -++ gdb_command_funnel_1(req); -++ } catch (const gdb_exception &ex) { -++ if (req->flags & GNU_RETURN_ON_ERROR) -++ req->flags |= GNU_COMMAND_FAILED; -++ else -++ throw ex; -++ } -++} -++ -++void -++gdb_command_funnel_1(struct gnu_request *req) -++{ -++ struct symbol *sym; -++ -++ if (req->command != GNU_VERSION && req->command != GNU_USER_PRINT_OPTION) { -++ (dynamic_castgdb_stdout)->set_stream(req->fp); -++ (dynamic_castgdb_stderr)->set_stream(req->fp); -++ } -++ -++ switch (req->command) -++ { -++ case GNU_VERSION: -++ req->buf = (char *)version; -++ break; -++ -++ case GNU_PASS_THROUGH: -++ execute_command(req->buf, -++ req->flags & GNU_FROM_TTY_OFF ? FALSE : TRUE); -++ break; -++ -++ case GNU_USER_PRINT_OPTION: -++ get_user_print_option_address(req); -++ break; -++ -++ case GNU_RESOLVE_TEXT_ADDR: -++ sym = find_pc_function(req->addr); -++ if (!sym || TYPE_CODE(sym->type) != TYPE_CODE_FUNC) -++ req->flags |= GNU_COMMAND_FAILED; -++ break; -++ -++ case GNU_DISASSEMBLE: -++ if (req->addr2) -++ sprintf(req->buf, "disassemble 0x%lx 0x%lx", -++ req->addr, req->addr2); -++ else -++ sprintf(req->buf, "disassemble 0x%lx", req->addr); -++ execute_command(req->buf, TRUE); -++ break; -++ -++ case GNU_ADD_SYMBOL_FILE: -++ gdb_add_symbol_file(req); -++ break; -++ -++ case GNU_DELETE_SYMBOL_FILE: -++ gdb_delete_symbol_file(req); -++ break; -++ -++ case GNU_GET_LINE_NUMBER: -++ gdb_get_line_number(req); -++ break; -++ -++ case GNU_GET_DATATYPE: -++ gdb_get_datatype(req); -++ break; -++ -++ case GNU_GET_SYMBOL_TYPE: -++ gdb_get_symbol_type(req); -++ break; -++ -++ case GNU_COMMAND_EXISTS: -++ gdb_command_exists(req); -++ break; -++ -++ case GNU_ALPHA_FRAME_OFFSET: -++ req->value = 0; -++ break; -++ -++ case GNU_FUNCTION_NUMARGS: -++ gdb_function_numargs(req); -++ break; -++ -++ case GNU_DEBUG_COMMAND: -++ gdb_debug_command(req); -++ break; -++ -++ case GNU_PATCH_SYMBOL_VALUES: -++ gdb_patch_symbol_values(req); -++ break; -++ -++ case GNU_SET_CRASH_BLOCK: -++ gdb_set_crash_block(req); -++ break; -++ -++ case GNU_GET_FUNCTION_RANGE: -++ { -++ CORE_ADDR start, end; -++ if (!find_pc_partial_function(req->pc, NULL, &start, &end)) -++ req->flags |= GNU_COMMAND_FAILED; -++ else { -++ req->addr = (ulong)start; -++ req->addr2 = (ulong)end; -++ } -++ } -++ break; -++ -++ case GNU_LOOKUP_STRUCT_CONTENTS: -++ req->value = lookup_struct_contents(req); -++ break; -++ -++ case GNU_ITERATE_DATATYPES: -++ iterate_datatypes(req); -++ break; -++ -++ default: -++ req->flags |= GNU_COMMAND_FAILED; -++ break; -++ } -++} -++ -++/* -++ * Given a PC value, return the file and line number. -++ */ -++static void -++gdb_get_line_number(struct gnu_request *req) -++{ -++ struct symtab_and_line sal; -++ struct objfile *objfile; -++ CORE_ADDR pc; -++ -++#define LASTCHAR(s) (s[strlen(s)-1]) -++ -++ /* -++ * Prime the addrmap pump. -++ */ -++ pc = req->addr; -++ -++ sal = find_pc_line(pc, 0); -++ -++ if (!sal.symtab) { -++ /* -++ * If a module address line number can't be found, it's typically -++ * due to its addrmap still containing offset values because its -++ * objfile doesn't have full symbols loaded. -++ */ -++ if (req->lm) { -++ objfile = req->lm->loaded_objfile; -++ if (!objfile_has_full_symbols(objfile) && objfile->sf) { -++ objfile->sf->qf->expand_all_symtabs(objfile); -++ sal = find_pc_line(pc, 0); -++ } -++ } -++ if (!sal.symtab) { -++ req->buf[0] = '\0'; -++ return; -++ } -++ } -++ -++ if (sal.symtab->filename && SYMTAB_DIRNAME(sal.symtab)) { -++ if (sal.symtab->filename[0] == '/') -++ sprintf(req->buf, "%s: %d", -++ sal.symtab->filename, sal.line); -++ else -++ sprintf(req->buf, "%s%s%s: %d", -++ SYMTAB_DIRNAME(sal.symtab), -++ LASTCHAR(SYMTAB_DIRNAME(sal.symtab)) == '/' ? "" : "/", -++ sal.symtab->filename, sal.line); -++ } -++} -++ -++/* -++ * General purpose routine for determining datatypes. -++ */ -++ -++static void -++gdb_get_datatype(struct gnu_request *req) -++{ -++ register struct type *type; -++ register struct type *typedef_type; -++ expression_up expr; -++ struct symbol *sym; -++ struct value *val; -++ -++ if (gdb_CRASHDEBUG(2)) -++ console("gdb_get_datatype [%s] (a)\n", req->name); -++ -++ req->typecode = TYPE_CODE_UNDEF; -++ -++ /* -++ * lookup_symbol() will pick up struct and union names. -++ */ -++ sym = lookup_symbol(req->name, 0, STRUCT_DOMAIN, 0).symbol; -++ if (sym) { -++ req->typecode = TYPE_CODE(sym->type); -++ req->length = TYPE_LENGTH(sym->type); -++ if (req->member) -++ get_member_data(req, sym->type, 0, 1); -++ -++ if (TYPE_CODE(sym->type) == TYPE_CODE_ENUM) { -++ if (req->flags & GNU_PRINT_ENUMERATORS) -++ dump_enum(sym->type, req); -++ } -++ -++ return; -++ } -++ -++ /* -++ * Otherwise parse the expression. -++ */ -++ if (gdb_CRASHDEBUG(2)) -++ console("gdb_get_datatype [%s] (b)\n", req->name); -++ -++ expr = parse_expression(req->name); -++ -++ -++ switch (expr.get()->elts[0].opcode) -++ { -++ case OP_VAR_VALUE: -++ if (gdb_CRASHDEBUG(2)) -++ console("expr->elts[0].opcode: OP_VAR_VALUE\n"); -++ type = expr.get()->elts[2].symbol->type; -++ if (req->flags & GNU_VAR_LENGTH_TYPECODE) { -++ req->typecode = TYPE_CODE(type); -++ req->length = TYPE_LENGTH(type); -++ } -++ if (TYPE_CODE(type) == TYPE_CODE_ENUM) { -++ req->typecode = TYPE_CODE(type); -++ req->value = SYMBOL_VALUE(expr.get()->elts[2].symbol); -++ req->tagname = (char *)TYPE_TAG_NAME(type); -++ if (!req->tagname) { -++ val = evaluate_type(expr.get()); -++ eval_enum(value_type(val), req); -++ } -++ } -++ break; -++ -++ case OP_TYPE: -++ if (gdb_CRASHDEBUG(2)) -++ console("expr->elts[0].opcode: OP_TYPE\n"); -++ type = expr.get()->elts[1].type; -++ -++ req->typecode = TYPE_CODE(type); -++ req->length = TYPE_LENGTH(type); -++ -++ if (TYPE_CODE(type) == TYPE_CODE_TYPEDEF) { -++ req->is_typedef = TYPE_CODE_TYPEDEF; -++ if ((typedef_type = check_typedef(type))) { -++ req->typecode = TYPE_CODE(typedef_type); -++ req->length = TYPE_LENGTH(typedef_type); -++ type = typedef_type; -++ } -++ } -++ -++ if (TYPE_CODE(type) == TYPE_CODE_ENUM) { -++ if (req->is_typedef) -++ if (req->flags & GNU_PRINT_ENUMERATORS) { -++ if (req->is_typedef) -++ fprintf_filtered(gdb_stdout, -++ "typedef "); -++ dump_enum(type, req); -++ } -++ } -++ -++ if (req->member) -++ get_member_data(req, type, 0, 1); -++ -++ break; -++ -++ default: -++ if (gdb_CRASHDEBUG(2)) -++ console("expr.get()->elts[0].opcode: %d (?)\n", -++ expr.get()->elts[0].opcode); -++ break; -++ -++ } -++} -++ -++/* -++ * More robust enum list dump that gdb's, showing the value of each -++ * identifier, each on its own line. -++ */ -++static void -++dump_enum(struct type *type, struct gnu_request *req) -++{ -++ register int i; -++ int len; -++ long long lastval; -++ -++ len = TYPE_NFIELDS (type); -++ lastval = 0; -++ if (TYPE_TAG_NAME(type)) -++ fprintf_filtered(gdb_stdout, -++ "enum %s {\n", TYPE_TAG_NAME (type)); -++ else -++ fprintf_filtered(gdb_stdout, "enum {\n"); -++ -++ for (i = 0; i < len; i++) { -++ fprintf_filtered(gdb_stdout, " %s", -++ TYPE_FIELD_NAME (type, i)); -++ if (lastval != TYPE_FIELD_ENUMVAL (type, i)) { -++ fprintf_filtered (gdb_stdout, " = %s", -++ plongest(TYPE_FIELD_ENUMVAL (type, i))); -++ lastval = TYPE_FIELD_ENUMVAL (type, i); -++ } else -++ fprintf_filtered(gdb_stdout, " = %s", plongest(lastval)); -++ fprintf_filtered(gdb_stdout, "\n"); -++ lastval++; -++ } -++ if (TYPE_TAG_NAME(type)) -++ fprintf_filtered(gdb_stdout, "};\n"); -++ else -++ fprintf_filtered(gdb_stdout, "} %s;\n", req->name); -++} -++ -++/* -++ * Given an enum type with no tagname, determine its value. -++ */ -++static void -++eval_enum(struct type *type, struct gnu_request *req) -++{ -++ register int i; -++ int len; -++ long long lastval; -++ -++ len = TYPE_NFIELDS (type); -++ lastval = 0; -++ -++ for (i = 0; i < len; i++) { -++ if (lastval != TYPE_FIELD_ENUMVAL (type, i)) -++ lastval = TYPE_FIELD_ENUMVAL (type, i); -++ -++ if (STREQ(TYPE_FIELD_NAME(type, i), req->name)) { -++ req->tagname = "(unknown)"; -++ req->value = lastval; -++ return; -++ } -++ lastval++; -++ } -++} -++ -++/* -++ * Walk through a struct type's list of fields looking for the desired -++ * member field, and when found, return its relevant data. -++ */ -++static void -++get_member_data(struct gnu_request *req, struct type *type, long offset, int is_first) -++{ -++ register short i; -++ struct field *nextfield; -++ short nfields; -++ struct type *typedef_type, *target_type; -++ -++ req->member_offset = -1; -++ -++ nfields = TYPE_MAIN_TYPE(type)->nfields; -++ nextfield = TYPE_MAIN_TYPE(type)->flds_bnds.fields; -++ -++ if (nfields == 0 && is_first /* The first call */) { -++ struct type *newtype; -++ newtype = lookup_transparent_type(req->name); -++ if (newtype) { -++ console("get_member_data(%s.%s): switching type from %lx to %lx\n", -++ req->name, req->member, type, newtype); -++ nfields = TYPE_MAIN_TYPE(newtype)->nfields; -++ nextfield = TYPE_MAIN_TYPE(newtype)->flds_bnds.fields; -++ } -++ } -++ -++ for (i = 0; i < nfields; i++) { -++ if (STREQ(req->member, nextfield->name)) { -++ req->member_offset = offset + nextfield->loc.bitpos; -++ req->member_length = TYPE_LENGTH(nextfield->type); -++ req->member_typecode = TYPE_CODE(nextfield->type); -++ req->member_main_type_name = (char *)TYPE_NAME(nextfield->type); -++ req->member_main_type_tag_name = (char *)TYPE_TAG_NAME(nextfield->type); -++ target_type = TYPE_TARGET_TYPE(nextfield->type); -++ if (target_type) { -++ req->member_target_type_name = (char *)TYPE_NAME(target_type); -++ req->member_target_type_tag_name = (char *)TYPE_TAG_NAME(target_type); -++ } -++ if ((req->member_typecode == TYPE_CODE_TYPEDEF) && -++ (typedef_type = check_typedef(nextfield->type))) -++ req->member_length = TYPE_LENGTH(typedef_type); -++ return; -++ } else if (*nextfield->name == 0) { /* Anonymous struct/union */ -++ get_member_data(req, nextfield->type, -++ offset + nextfield->loc.bitpos, 0); -++ if (req->member_offset != -1) -++ return; -++ } -++ nextfield++; -++ } -++} -++ -++/* -++ * Check whether a command exists. If it doesn't, the command will be -++ * returned indirectly via the error_hook. -++ */ -++static void -++gdb_command_exists(struct gnu_request *req) -++{ -++ extern struct cmd_list_element *cmdlist; -++ -++ req->value = FALSE; -++ lookup_cmd((const char **)&req->name, cmdlist, "", 0, 1); -++ req->value = TRUE; -++} -++ -++static void -++gdb_function_numargs(struct gnu_request *req) -++{ -++ struct symbol *sym; -++ -++ sym = find_pc_function(req->pc); -++ -++ if (!sym || TYPE_CODE(sym->type) != TYPE_CODE_FUNC) { -++ req->flags |= GNU_COMMAND_FAILED; -++ return; -++ } -++ -++ req->value = (ulong)TYPE_NFIELDS(sym->type); -++} -++ -++struct load_module *gdb_current_load_module = NULL; -++ -++static void -++gdb_add_symbol_file(struct gnu_request *req) -++{ -++ struct load_module *lm; -++ int i; -++ int allsect = 0; -++ char *secname; -++ char buf[80]; -++ struct objfile *objfile; -++ -++ gdb_current_load_module = lm = (struct load_module *)req->addr; -++ -++ req->name = lm->mod_namelist; -++ gdb_delete_symbol_file(req); -++ lm->loaded_objfile = NULL; -++ -++ if ((lm->mod_flags & MOD_NOPATCH) == 0) { -++ for (i = 0 ; i < lm->mod_sections; i++) { -++ if (STREQ(lm->mod_section_data[i].name, ".text") && -++ (lm->mod_section_data[i].flags & SEC_FOUND)) -++ allsect = 1; -++ } -++ -++ if (!allsect) { -++ sprintf(req->buf, "add-symbol-file %s 0x%lx %s", lm->mod_namelist, -++ lm->mod_text_start ? lm->mod_text_start : lm->mod_base, -++ lm->mod_flags & MOD_DO_READNOW ? "-readnow" : ""); -++ if (lm->mod_data_start) { -++ sprintf(buf, " -s .data 0x%lx", lm->mod_data_start); -++ strcat(req->buf, buf); -++ } -++ if (lm->mod_bss_start) { -++ sprintf(buf, " -s .bss 0x%lx", lm->mod_bss_start); -++ strcat(req->buf, buf); -++ } -++ if (lm->mod_rodata_start) { -++ sprintf(buf, " -s .rodata 0x%lx", lm->mod_rodata_start); -++ strcat(req->buf, buf); -++ } -++ } else { -++ sprintf(req->buf, "add-symbol-file %s 0x%lx %s", lm->mod_namelist, -++ lm->mod_text_start, lm->mod_flags & MOD_DO_READNOW ? -++ "-readnow" : ""); -++ for (i = 0; i < lm->mod_sections; i++) { -++ secname = lm->mod_section_data[i].name; -++ if ((lm->mod_section_data[i].flags & SEC_FOUND) && -++ !STREQ(secname, ".text")) { -++ sprintf(buf, " -s %s 0x%lx", secname, -++ lm->mod_section_data[i].offset + lm->mod_base); -++ strcat(req->buf, buf); -++ } -++ } -++ } -++ } -++ -++ if (gdb_CRASHDEBUG(1)) -++ fprintf_filtered(gdb_stdout, "%s\n", req->buf); -++ -++ execute_command(req->buf, FALSE); -++ -++ ALL_OBJFILES (objfile) { -++ if (same_file((char *)objfile_name(objfile), lm->mod_namelist)) { -++ if (objfile->separate_debug_objfile) -++ lm->loaded_objfile = objfile->separate_debug_objfile; -++ else -++ lm->loaded_objfile = objfile; -++ break; -++ } -++ } -++ -++ if (!lm->loaded_objfile) -++ req->flags |= GNU_COMMAND_FAILED; -++} -++ -++static void -++gdb_delete_symbol_file(struct gnu_request *req) -++{ -++ register struct objfile *objfile; -++ -++ ALL_OBJFILES (objfile) { -++ if (STREQ(objfile_name(objfile), req->name) || -++ same_file((char *)objfile_name(objfile), req->name)) { -++ delete objfile; -++ break; -++ } -++ } -++ -++ if (gdb_CRASHDEBUG(2)) { -++ fprintf_filtered(gdb_stdout, "current object files:\n"); -++ ALL_OBJFILES (objfile) { -++ fprintf_filtered(gdb_stdout, " %s\n", objfile_name(objfile)); -++ } -++ } -++} -++/* -++ * Walk through all minimal_symbols, patching their values with the -++ * correct addresses. -++ */ -++static void -++gdb_patch_symbol_values(struct gnu_request *req) -++{ -++ struct objfile *objfile; -++ struct minimal_symbol *msymbol; -++ -++ req->name = PATCH_KERNEL_SYMBOLS_START; -++ patch_kernel_symbol(req); -++ -++ ALL_MSYMBOLS (objfile, msymbol) -++ { -++ req->name = (char *)msymbol->mginfo.name; -++ req->addr = (ulong)(&MSYMBOL_VALUE(msymbol)); -++ if (!patch_kernel_symbol(req)) { -++ req->flags |= GNU_COMMAND_FAILED; -++ break; -++ } -++ } -++ -++ req->name = PATCH_KERNEL_SYMBOLS_STOP; -++ patch_kernel_symbol(req); -++ -++ clear_symtab_users(0); -++ gdb_merge_flags |= KERNEL_SYMBOLS_PATCHED; -++} -++ -++static void -++gdb_get_symbol_type(struct gnu_request *req) -++{ -++ expression_up expr; -++ struct value *val; -++ struct type *type; -++ struct type *target_type; -++ -++ req->typecode = TYPE_CODE_UNDEF; -++ -++ expr = parse_expression (req->name); -++ val = evaluate_type (expr.get()); -++ -++ type = value_type(val); -++ -++ req->type_name = (char *)TYPE_MAIN_TYPE(type)->name; -++ req->typecode = TYPE_MAIN_TYPE(type)->code; -++ req->length = type->length; -++ req->type_tag_name = (char *)TYPE_TAG_NAME(type); -++ target_type = TYPE_MAIN_TYPE(type)->target_type; -++ -++ if (target_type) { -++ req->target_typename = (char *)TYPE_MAIN_TYPE(target_type)->name; -++ req->target_typecode = TYPE_MAIN_TYPE(target_type)->code; -++ req->target_length = target_type->length; -++ } -++ -++ if (req->member) -++ get_member_data(req, type, 0, 1); -++} -++ -++static void -++gdb_debug_command(struct gnu_request *req) -++{ -++ -++ } -++ -++/* -++ * Only necessary on "patched" kernel symbol sessions, and called only by -++ * lookup_symbol(), pull a symbol value bait-and-switch operation by altering -++ * either a data symbol's address value or a text symbol's block start address. -++ */ -++static void -++gdb_bait_and_switch(char *name, struct symbol *sym) -++{ -++ struct bound_minimal_symbol msym; -++ struct block *block; -++ -++ if ((gdb_merge_flags & KERNEL_SYMBOLS_PATCHED) && -++ (msym = lookup_minimal_symbol(name, NULL, gdb_kernel_objfile)).minsym) { -++ if (SYMBOL_CLASS (sym) == LOC_BLOCK) { -++ block = (struct block *)SYMBOL_BLOCK_VALUE (sym); -++ BLOCK_START (block) = BMSYMBOL_VALUE_ADDRESS (msym); -++ } else -++ SYMBOL_VALUE_ADDRESS (sym) = BMSYMBOL_VALUE_ADDRESS (msym); -++ } -++} -++ -++#include "valprint.h" -++ -++void -++get_user_print_option_address(struct gnu_request *req) -++{ -++ extern struct value_print_options user_print_options; -++ -++ req->addr = 0; -++ -++ if (strcmp(req->name, "output_format") == 0) -++ req->addr = (ulong)&user_print_options.output_format; -++ if (strcmp(req->name, "print_max") == 0) -++ req->addr = (ulong)&user_print_options.print_max; -++ if (strcmp(req->name, "prettyprint_structs") == 0) -++ req->addr = (ulong)&user_print_options.prettyformat_structs; -++ if (strcmp(req->name, "prettyprint_arrays") == 0) -++ req->addr = (ulong)&user_print_options.prettyformat_arrays; -++ if (strcmp(req->name, "repeat_count_threshold") == 0) -++ req->addr = (ulong)&user_print_options.repeat_count_threshold; -++ if (strcmp(req->name, "stop_print_at_null") == 0) -++ req->addr = (ulong)&user_print_options.stop_print_at_null; -++ if (strcmp(req->name, "output_radix") == 0) -++ req->addr = (ulong)&output_radix; -++} -++ -++CORE_ADDR crash_text_scope; -++ -++static void -++gdb_set_crash_block(struct gnu_request *req) -++{ -++ if (!req->addr) { /* debug */ -++ crash_text_scope = 0; -++ return; -++ } -++ -++ if ((req->addr2 = (ulong)block_for_pc(req->addr))) -++ crash_text_scope = req->addr; -++ else { -++ crash_text_scope = 0; -++ req->flags |= GNU_COMMAND_FAILED; -++ } -++} -++ -++static const struct block * -++gdb_get_crash_block(void) -++{ -++ if (crash_text_scope) -++ return block_for_pc(crash_text_scope); -++ else -++ return NULL; -++} -++ -++static long -++lookup_struct_contents(struct gnu_request *req) -++{ -++ int i; -++ long r; -++ struct field *f; -++ struct main_type *m; -++ const char *n; -++ struct main_type *top_m = (struct main_type *)req->addr; -++ char *type_name = req->type_name; -++ -++ if (!top_m || !type_name) -++ return 0; -++ -++ for (i = 0; i < top_m->nfields; i++) -++ { -++ f = top_m->flds_bnds.fields + i; -++ if (!f->type) -++ continue; -++ m = f->type->main_type; -++ -++ // If the field is an array, check the target type - -++ // it might be structure, or might not be. -++ // - struct request_sock *syn_table[0]; -++ // here m->target_type->main_type->code is expected -++ // to be TYPE_CODE_PTR -++ // - struct list_head vec[TVN_SIZE]; -++ // here m->target_type->main_type->code should be -++ // TYPE_CODE_STRUCT -++ if (m->code == TYPE_CODE_ARRAY && m->target_type) -++ m = m->target_type->main_type; -++ -++ /* Here is a recursion. -++ * If we have struct variable (not pointer), -++ * scan this inner structure -++ */ -++ if (m->code == TYPE_CODE_STRUCT) { -++ req->addr = (ulong)m; -++ r = lookup_struct_contents(req); -++ req->addr = (ulong)top_m; -++ if (r) -++ return 1; -++ } -++ -++ if (m->code == TYPE_CODE_PTR && m->target_type) -++ m = m->target_type->main_type; -++ if (m->name) -++ n = m->name; -++ else -++ continue; -++ -++ if (strstr(n, type_name)) -++ return 1; -++ } -++ -++ return 0; -++} -++ -++static void -++iterate_datatypes (struct gnu_request *req) -++{ -++ struct objfile *objfile; -++ struct compunit_symtab *compunit_symtabs = NULL; -++ -++ ALL_OBJFILES(objfile) -++ { -++ if (objfile->sf) -++ objfile->sf->qf->expand_all_symtabs(objfile); -++ } -++ -++ ALL_COMPUNITS (objfile, compunit_symtabs) -++ { -++ const struct blockvector *bv = COMPUNIT_BLOCKVECTOR (compunit_symtabs); -++ -++ for (int i = GLOBAL_BLOCK; i <= STATIC_BLOCK; ++i) -++ { -++ const struct block *b = BLOCKVECTOR_BLOCK (bv, i); -++ struct block_iterator iter; -++ struct symbol *sym; -++ -++ ALL_BLOCK_SYMBOLS (b, iter, sym) -++ { -++ QUIT; -++ -++ if (SYMBOL_CLASS (sym) != LOC_TYPEDEF) -++ continue; -++ -++ if (req->highest && -++ !(req->lowest <= sym->type->length && sym->type->length <= req->highest)) -++ continue; -++ -++ req->addr = (ulong)(sym->type->main_type); -++ req->name = (char *)(sym->ginfo.name); -++ req->length = sym->type->length; -++ -++ if (req->member) { -++ req->value = lookup_struct_contents(req); -++ if (!req->value) -++ continue; -++ } -++ req->callback(req, req->callback_data); -++ } -++ } -++ } -++} -++ -++#endif -+diff -aurp gdb-8.1.orig/gdb/ui-file.h gdb-8.1/gdb/ui-file.h -+--- gdb-8.1.orig/gdb/ui-file.h 2021-06-04 09:43:28.501372153 +0800 -++++ gdb-8.1/gdb/ui-file.h 2021-06-04 10:49:01.540989434 +0800 -+@@ -180,11 +180,11 @@ public: -+ -+ bool isatty () override; -+ -+-private: -+ /* Sets the internal stream to FILE, and saves the FILE's file -+ descriptor in M_FD. */ -+ void set_stream (FILE *file); -+ -++private: -+ /* The file. */ -+ FILE *m_file; -+ -+diff -aurp gdb-8.1.orig/gdb/xml-syscall.c gdb-8.1/gdb/xml-syscall.c -+--- gdb-8.1.orig/gdb/xml-syscall.c 2021-06-04 09:43:28.497372139 +0800 -++++ gdb-8.1/gdb/xml-syscall.c 2021-06-04 10:49:01.540989434 +0800 -+@@ -37,7 +37,11 @@ -+ static void -+ syscall_warn_user (void) -+ { -++#ifdef CRASH_MERGE -++ static int have_warned = 1; -++#else -+ static int have_warned = 0; -++#endif -+ if (!have_warned) -+ { -+ have_warned = 1; -+diff -aurp gdb-8.1.orig/libiberty/Makefile.in gdb-8.1/libiberty/Makefile.in -+--- gdb-8.1.orig/libiberty/Makefile.in 2021-06-04 09:43:29.437375356 +0800 -++++ gdb-8.1/libiberty/Makefile.in 2021-06-04 10:49:01.544989434 +0800 -+@@ -177,6 +177,7 @@ REQUIRED_OFILES = \ -+ ./getruntime.$(objext) ./hashtab.$(objext) ./hex.$(objext) \ -+ ./lbasename.$(objext) ./lrealpath.$(objext) \ -+ ./make-relative-prefix.$(objext) ./make-temp-file.$(objext) \ -++ ./mkstemps.$(objext) \ -+ ./objalloc.$(objext) \ -+ ./obstack.$(objext) \ -+ ./partition.$(objext) ./pexecute.$(objext) ./physmem.$(objext) \ -+@@ -210,7 +211,7 @@ CONFIGURED_OFILES = ./asprintf.$(objext) -+ ./index.$(objext) ./insque.$(objext) \ -+ ./memchr.$(objext) ./memcmp.$(objext) ./memcpy.$(objext) \ -+ ./memmem.$(objext) ./memmove.$(objext) \ -+- ./mempcpy.$(objext) ./memset.$(objext) ./mkstemps.$(objext) \ -++ ./mempcpy.$(objext) ./memset.$(objext) \ -+ ./pex-djgpp.$(objext) ./pex-msdos.$(objext) \ -+ ./pex-unix.$(objext) ./pex-win32.$(objext) \ -+ ./putenv.$(objext) \ -+diff -aurp gdb-8.1.orig/Makefile.in gdb-8.1/Makefile.in -+--- gdb-8.1.orig/Makefile.in 2021-06-04 09:43:29.457375425 +0800 -++++ gdb-8.1/Makefile.in 2021-06-04 10:49:01.544989434 +0800 -+@@ -340,6 +340,9 @@ AR_FOR_BUILD = @AR_FOR_BUILD@ -+ AS_FOR_BUILD = @AS_FOR_BUILD@ -+ CC_FOR_BUILD = @CC_FOR_BUILD@ -+ CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@ -++ifeq (${CRASH_TARGET}, PPC64) -++CFLAGS_FOR_BUILD += -m64 -fPIC -++endif -+ CXXFLAGS_FOR_BUILD = @CXXFLAGS_FOR_BUILD@ -+ CXX_FOR_BUILD = @CXX_FOR_BUILD@ -+ DLLTOOL_FOR_BUILD = @DLLTOOL_FOR_BUILD@ -+@@ -405,7 +408,10 @@ WINDMC = @WINDMC@ -+ GNATBIND = @GNATBIND@ -+ GNATMAKE = @GNATMAKE@ -+ -+-CFLAGS = @CFLAGS@ -++CFLAGS = @CFLAGS@ -Wno-implicit-fallthrough -Wno-unused-value -Wno-unused-const-variable -++ifeq (${CRASH_TARGET}, PPC64) -++CFLAGS += -m64 -fPIC -++endif -+ LDFLAGS = @LDFLAGS@ -+ LIBCFLAGS = $(CFLAGS) -+ CXXFLAGS = @CXXFLAGS@ -+diff -aurp gdb-8.1.orig/opcodes/i386-dis.c gdb-8.1/opcodes/i386-dis.c -+--- gdb-8.1.orig/opcodes/i386-dis.c 2021-06-04 09:43:29.469375466 +0800 -++++ gdb-8.1/opcodes/i386-dis.c 2021-06-04 09:43:30.745379834 +0800 -+@@ -13396,6 +13396,10 @@ print_insn (bfd_vma pc, disassemble_info -+ threebyte = *codep; -+ dp = &dis386_twobyte[threebyte]; -+ need_modrm = twobyte_has_modrm[*codep]; -++ if (dp->name && ((strcmp(dp->name, "ud2a") == 0) || (strcmp(dp->name, "ud2") == 0))) { -++ extern int kernel_BUG_encoding_bytes(void); -++ codep += kernel_BUG_encoding_bytes(); -++ } -+ codep++; -+ } -+ else -+diff -aurp gdb-8.1.orig/readline/misc.c gdb-8.1/readline/misc.c -+--- gdb-8.1.orig/readline/misc.c 2021-06-04 09:43:29.673376164 +0800 -++++ gdb-8.1/readline/misc.c 2021-06-04 10:49:01.544989434 +0800 -+@@ -405,7 +405,7 @@ _rl_history_set_point () -+ -+ #if defined (VI_MODE) -+ if (rl_editing_mode == vi_mode && _rl_keymap != vi_insertion_keymap) -+- rl_point = 0; -++ rl_point = rl_end; -+ #endif /* VI_MODE */ -+ -+ if (rl_editing_mode == emacs_mode) -+diff -aurp gdb-8.1.orig/readline/readline.h gdb-8.1/readline/readline.h -+--- gdb-8.1.orig/readline/readline.h 2021-06-04 09:43:29.669376150 +0800 -++++ gdb-8.1/readline/readline.h 2021-06-04 10:49:01.548989434 +0800 -+@@ -378,7 +378,7 @@ extern int rl_crlf PARAMS((void)); -+ #if defined (USE_VARARGS) && defined (PREFER_STDARG) -+ extern int rl_message (const char *, ...) __attribute__((__format__ (printf, 1, 2))); -+ #else -+-extern int rl_message (); -++extern int rl_message (void); -+ #endif -+ -+ extern int rl_show_char PARAMS((int)); -+diff -aurp gdb-8.1.orig/readline/rltypedefs.h gdb-8.1/readline/rltypedefs.h -+--- gdb-8.1.orig/readline/rltypedefs.h 2021-06-04 09:43:29.677376178 +0800 -++++ gdb-8.1/readline/rltypedefs.h 2021-06-04 10:49:01.548989434 +0800 -+@@ -31,10 +31,10 @@ extern "C" { -+ #if !defined (_FUNCTION_DEF) -+ # define _FUNCTION_DEF -+ -+-typedef int Function (); -+-typedef void VFunction (); -+-typedef char *CPFunction (); -+-typedef char **CPPFunction (); -++typedef int Function (void); -++typedef void VFunction (void); -++typedef char *CPFunction (void); -++typedef char **CPPFunction (void); -+ -+ #endif /* _FUNCTION_DEF */ -+ -+diff -aurp gdb-8.1.orig/readline/util.c gdb-8.1/readline/util.c -+--- gdb-8.1.orig/readline/util.c 2021-06-04 09:43:29.677376178 +0800 -++++ gdb-8.1/readline/util.c 2021-06-04 10:49:01.548989434 +0800 -+@@ -494,10 +494,13 @@ _rl_trace (va_alist) -+ -+ if (_rl_tracefp == 0) -+ _rl_tropen (); -++ if (!_rl_tracefp) -++ goto out; -+ vfprintf (_rl_tracefp, format, args); -+ fprintf (_rl_tracefp, "\n"); -+ fflush (_rl_tracefp); -+ -++out: -+ va_end (args); -+ } -+ -+@@ -520,16 +523,17 @@ _rl_tropen () -+ sprintf (fnbuf, "/var/tmp/rltrace.%ld", getpid()); -+ #endif -+ unlink(fnbuf); -+- _rl_tracefp = fopen (fnbuf, "w+"); -++ _rl_tracefp = fopen (fnbuf, "w+xe"); -+ return _rl_tracefp != 0; -+ } -+ -+ int -+ _rl_trclose () -+ { -+- int r; -++ int r = 0; -+ -+- r = fclose (_rl_tracefp); -++ if (_rl_tracefp) -++ r = fclose (_rl_tracefp); -+ _rl_tracefp = 0; -+ return r; -+ } -diff --git a/gdb_interface.c b/gdb_interface.c -index 1f10006..ad5f17b 100644 ---- a/gdb_interface.c -+++ b/gdb_interface.c -@@ -17,18 +17,21 @@ - - #include "defs.h" - -+#ifndef GDB_8_1 - static void exit_after_gdb_info(void); -+#endif - static int is_restricted_command(char *, ulong); - static void strip_redirection(char *); - int get_frame_offset(ulong); - - int *gdb_output_format; - unsigned int *gdb_print_max; --int *gdb_prettyprint_structs; --int *gdb_prettyprint_arrays; --int *gdb_repeat_count_threshold; --int *gdb_stop_print_at_null; -+unsigned char *gdb_prettyprint_structs; -+unsigned char *gdb_prettyprint_arrays; -+unsigned int *gdb_repeat_count_threshold; -+unsigned char *gdb_stop_print_at_null; - unsigned int *gdb_output_radix; -+static void gdb_error_debug(void); - - static ulong gdb_user_print_option_address(char *); - -@@ -68,10 +71,12 @@ gdb_main_loop(int argc, char **argv) - } - - optind = 0; -+#ifndef GDB_8_1 - #if defined(GDB_5_3) || defined(GDB_6_0) || defined(GDB_6_1) - command_loop_hook = main_loop; - #else - deprecated_command_loop_hook = main_loop; -+#endif - #endif - gdb_main_entry(argc, argv); - } -@@ -117,22 +122,26 @@ void - display_gdb_banner(void) - { - optind = 0; -+#ifndef GDB_8_1 - #if defined(GDB_5_3) || defined(GDB_6_0) || defined(GDB_6_1) - command_loop_hook = exit_after_gdb_info; - #else - deprecated_command_loop_hook = exit_after_gdb_info; -+#endif - #endif - args[0] = "gdb"; - args[1] = "-version"; - gdb_main_entry(2, args); - } - -+#ifndef GDB_8_1 - static void - exit_after_gdb_info(void) - { - fprintf(fp, "\n"); - clean_exit(0); - } -+#endif - - /* - * Stash a copy of the gdb version locally. This can be called before -@@ -186,13 +195,13 @@ gdb_session_init(void) - gdb_user_print_option_address("output_format"); - gdb_print_max = (unsigned int *) - gdb_user_print_option_address("print_max"); -- gdb_prettyprint_structs = (int *) -+ gdb_prettyprint_structs = (unsigned char *) - gdb_user_print_option_address("prettyprint_structs"); -- gdb_prettyprint_arrays = (int *) -+ gdb_prettyprint_arrays = (unsigned char *) - gdb_user_print_option_address("prettyprint_arrays"); -- gdb_repeat_count_threshold = (int *) -+ gdb_repeat_count_threshold = (unsigned int *) - gdb_user_print_option_address("repeat_count_threshold"); -- gdb_stop_print_at_null = (int *) -+ gdb_stop_print_at_null = (unsigned char *) - gdb_user_print_option_address("stop_print_at_null"); - gdb_output_radix = (unsigned int *) - gdb_user_print_option_address("output_radix"); -@@ -291,6 +300,7 @@ retry: - sprintf(req->buf, "set width 0"); - gdb_interface(req); - -+#if 0 - /* - * Patch gdb's symbol values with the correct values from either - * the System.map or non-debug vmlinux, whichever is in effect. -@@ -303,9 +313,13 @@ retry: - if (req->flags & GNU_COMMAND_FAILED) - error(FATAL, "patching of gdb symbol values failed\n"); - } else if (!(pc->flags & SILENT)) -+#else -+ if (!(pc->flags & SILENT)) -+#endif - fprintf(fp, "\n"); - - -+ - FREEBUF(req->buf); - FREEBUF(req); - } -@@ -364,19 +378,6 @@ gdb_interface(struct gnu_request *req) - pc->cur_req = req; - pc->cur_gdb_cmd = req->command; - -- if (req->flags & GNU_RETURN_ON_ERROR) { -- error_hook = gdb_error_hook; -- if (setjmp(pc->gdb_interface_env)) { -- pc->last_gdb_cmd = pc->cur_gdb_cmd; -- pc->cur_gdb_cmd = 0; -- pc->cur_req = NULL; -- req->flags |= GNU_COMMAND_FAILED; -- pc->flags &= ~IN_GDB; -- return; -- } -- } else -- error_hook = NULL; -- - if (CRASHDEBUG(2)) - dump_gnu_request(req, IN_GDB); - -@@ -400,10 +401,12 @@ gdb_interface(struct gnu_request *req) - SIGACTION(SIGINT, restart, &pc->sigaction, NULL); - SIGACTION(SIGSEGV, SIG_DFL, &pc->sigaction, NULL); - -+ if (req->flags & GNU_COMMAND_FAILED) -+ gdb_error_debug(); -+ - if (CRASHDEBUG(2)) - dump_gnu_request(req, !IN_GDB); - -- error_hook = NULL; - pc->last_gdb_cmd = pc->cur_gdb_cmd; - pc->cur_gdb_cmd = 0; - pc->cur_req = NULL; -@@ -627,8 +630,6 @@ restore_gdb_sanity(void) - *gdb_prettyprint_structs = 1; /* these may piss somebody off... */ - *gdb_repeat_count_threshold = 0x7fffffff; - -- error_hook = NULL; -- - if (st->flags & ADD_SYMBOL_FILE) { - error(INFO, - "%s\n gdb add-symbol-file command failed\n", -@@ -697,10 +698,9 @@ is_gdb_command(int merge_orig_args, ulong flags) - static char *prohibited_list[] = { - "run", "r", "break", "b", "tbreak", "hbreak", "thbreak", "rbreak", - "watch", "rwatch", "awatch", "attach", "continue", "c", "fg", "detach", -- "finish", "handle", "interrupt", "jump", "kill", "next", "nexti", -- "signal", "step", "s", "stepi", "target", "thread", "until", "delete", -- "clear", "disable", "enable", "condition", "ignore", "frame", -- "select-frame", "f", "up", "down", "catch", "tcatch", "return", -+ "finish", "handle", "interrupt", "jump", "kill", "next", "nexti", "signal", -+ "step", "s", "stepi", "target", "until", "delete", "clear", "disable", -+ "enable", "condition", "ignore", "catch", "tcatch", "return", - "file", "exec-file", "core-file", "symbol-file", "load", "si", "ni", - "shell", "sy", - NULL /* must be last */ -@@ -742,13 +742,6 @@ is_restricted_command(char *cmd, ulong flags) - } - } - -- if (kt->relocate && -- STRNEQ("disassemble", cmd) && STRNEQ(cmd, "disas")) -- error(FATAL, -- "the gdb \"disassemble\" command is prohibited because the kernel text\n" -- "%swas relocated%s; use the crash \"dis\" command instead.\n", -- space(strlen(pc->curcmd)+2), kt->flags2 & KASLR ? " by KASLR" : ""); -- - return FALSE; - } - -@@ -948,8 +941,8 @@ gdb_print_callback(ulong addr) - /* - * Used by gdb_interface() to catch gdb-related errors, if desired. - */ --void --gdb_error_hook(void) -+static void -+gdb_error_debug(void) - { - char buf1[BUFSIZE]; - char buf2[BUFSIZE]; -@@ -968,14 +961,6 @@ gdb_error_hook(void) - console("%s: returned via gdb_error_hook %s", - gdb_command_string(pc->cur_gdb_cmd, buf1, TRUE), buf2); - } -- --#ifdef GDB_7_6 -- do_cleanups(all_cleanups()); --#else -- do_cleanups(NULL); --#endif -- -- longjmp(pc->gdb_interface_env, 1); - } - - -@@ -1065,4 +1050,37 @@ get_frame_offset(ulong pc) - } - #endif /* !ALPHA */ - -+unsigned long crash_get_kaslr_offset(void); -+unsigned long crash_get_kaslr_offset(void) -+{ -+ return kt->relocate * -1; -+} -+ -+/* Callbacks for crash_target */ -+int crash_get_nr_cpus(void); -+int crash_get_cpu_reg (int cpu, int regno, const char *regname, -+ int regsize, void *val); -+ -+int crash_get_nr_cpus(void) -+{ -+ if (SADUMP_DUMPFILE()) -+ return sadump_get_nr_cpus(); -+ else if (DISKDUMP_DUMPFILE()) -+ return diskdump_get_nr_cpus(); -+ else if (KDUMP_DUMPFILE()) -+ return kdump_get_nr_cpus(); -+ else if (VMSS_DUMPFILE()) -+ return vmware_vmss_get_nr_cpus(); -+ -+ /* Just CPU #0 */ -+ return 1; -+} -+ -+int crash_get_cpu_reg (int cpu, int regno, const char *regname, -+ int regsize, void *value) -+{ -+ if (!machdep->get_cpu_reg) -+ return FALSE; -+ return machdep->get_cpu_reg(cpu, regno, regname, regsize, value); -+} - -diff --git a/help.c b/help.c -index e221607..cb3c2c1 100644 ---- a/help.c -+++ b/help.c -@@ -8304,6 +8304,7 @@ char *version_info[] = { - "Copyright (C) 2005, 2011, 2020-2021 NEC Corporation", - "Copyright (C) 1999, 2002, 2007 Silicon Graphics, Inc.", - "Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc.", -+"Copyright (C) 2015, 2021 VMware, Inc.", - "This program is free software, covered by the GNU General Public License,", - "and you are welcome to change it and/or distribute copies of it under", - "certain conditions. Enter \"help copying\" to see the conditions.", -@@ -9358,8 +9359,8 @@ char *README[] = { - " These are the current prerequisites: ", - "", - " o At this point, x86, ia64, x86_64, ppc64, ppc, arm, arm64, alpha, mips,", --" mips64, s390 and s390x-based kernels are supported. Other architectures", --" may be addressed in the future.", -+" mips64, loongarch64, s390 and s390x-based kernels are supported. Other", -+" architectures may be addressed in the future.", - "", - " o One size fits all -- the utility can be run on any Linux kernel version", - " version dating back to 2.2.5-15. A primary design goal is to always", -diff --git a/kernel.c b/kernel.c -index 8ae9e0c..be2616e 100644 ---- a/kernel.c -+++ b/kernel.c -@@ -1052,7 +1052,7 @@ verify_version(void) - - if (!(sp = symbol_search("linux_banner"))) - error(FATAL, "linux_banner symbol does not exist?\n"); -- else if ((sp->type == 'R') || (sp->type == 'r') || -+ else if ((sp->type == 'R') || (sp->type == 'r') || (sp->type == 'D') || - (machine_type("ARM") && sp->type == 'T') || - (machine_type("ARM64"))) - linux_banner = symbol_value("linux_banner"); -diff --git a/lkcd_vmdump_v1.h b/lkcd_vmdump_v1.h -index 4933427..841f150 100644 ---- a/lkcd_vmdump_v1.h -+++ b/lkcd_vmdump_v1.h -@@ -118,10 +118,12 @@ typedef struct _dump_header_s { - #ifndef S390 - #ifndef S390X - #ifndef ARM64 -+#ifndef LOONGARCH64 - struct pt_regs dh_regs; - #endif - #endif - #endif -+#endif - #endif - - /* the address of the current task */ -diff --git a/lkcd_vmdump_v2_v3.h b/lkcd_vmdump_v2_v3.h -index 984c2c2..ab395ea 100644 ---- a/lkcd_vmdump_v2_v3.h -+++ b/lkcd_vmdump_v2_v3.h -@@ -37,7 +37,7 @@ - - #if defined(ARM) || defined(X86) || defined(PPC) || defined(S390) || \ - defined(S390X) || defined(ARM64) || defined(MIPS) || \ -- defined(MIPS64) || defined(SPARC64) -+ defined(MIPS64) || defined(SPARC64) || defined(LOONGARCH64) - - /* - * Kernel header file for Linux crash dumps. -@@ -87,10 +87,12 @@ typedef struct _dump_header_asm_s { - #ifndef S390 - #ifndef S390X - #ifndef ARM64 -+#ifndef LOONGARCH64 - struct pt_regs dha_regs; - #endif - #endif - #endif -+#endif - - } dump_header_asm_t; - -diff --git a/loongarch64.c b/loongarch64.c -new file mode 100644 -index 0000000..867bd05 ---- /dev/null -+++ b/loongarch64.c -@@ -0,0 +1,1344 @@ -+/* loongarch64.c - core analysis suite -+ * -+ * Copyright (C) 2021 Loongson Technology Co., Ltd. -+ * -+ * 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 2 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. -+ */ -+ -+#ifdef LOONGARCH64 -+ -+#include -+#include "defs.h" -+ -+static int loongarch64_pgd_vtop(ulong *pgd, ulong vaddr, -+ physaddr_t *paddr, int verbose); -+static int loongarch64_uvtop(struct task_context *tc, ulong vaddr, -+ physaddr_t *paddr, int verbose); -+static int loongarch64_kvtop(struct task_context *tc, ulong kvaddr, -+ physaddr_t *paddr, int verbose); -+static int loongarch64_translate_pte(ulong pte, void *physaddr, -+ ulonglong pte64); -+ -+static void loongarch64_cmd_mach(void); -+static void loongarch64_display_machine_stats(void); -+ -+static void loongarch64_back_trace_cmd(struct bt_info *bt); -+static void loongarch64_analyze_function(ulong start, ulong offset, -+ struct loongarch64_unwind_frame *current, -+ struct loongarch64_unwind_frame *previous); -+static void loongarch64_dump_backtrace_entry(struct bt_info *bt, -+ struct syment *sym, struct loongarch64_unwind_frame *current, -+ struct loongarch64_unwind_frame *previous, int level); -+static void loongarch64_dump_exception_stack(struct bt_info *bt, char *pt_regs); -+static int loongarch64_is_exception_entry(struct syment *sym); -+static void loongarch64_display_full_frame(struct bt_info *bt, -+ struct loongarch64_unwind_frame *current, -+ struct loongarch64_unwind_frame *previous); -+static void loongarch64_stackframe_init(void); -+static void loongarch64_get_stack_frame(struct bt_info *bt, ulong *pcp, ulong *spp); -+static int loongarch64_get_dumpfile_stack_frame(struct bt_info *bt, -+ ulong *nip, ulong *ksp); -+static int loongarch64_get_frame(struct bt_info *bt, ulong *pcp, ulong *spp); -+static int loongarch64_init_active_task_regs(void); -+static int loongarch64_get_crash_notes(void); -+static int loongarch64_get_elf_notes(void); -+ -+/* -+ * 3 Levels paging PAGE_SIZE=16KB -+ * PGD | PMD | PTE | OFFSET | -+ * 11 | 11 | 11 | 14 | -+ */ -+/* From arch/loongarch/include/asm/pgtable{,-64}.h */ -+typedef struct { ulong pgd; } pgd_t; -+typedef struct { ulong pmd; } pmd_t; -+typedef struct { ulong pte; } pte_t; -+ -+#define TASK_SIZE64 (1UL << 40) -+ -+#define PMD_ORDER 0 -+#define PTE_ORDER 0 -+ -+#define PMD_SHIFT (PAGESHIFT() + (PAGESHIFT() + PTE_ORDER - 3)) -+#define PMD_SIZE (1UL << PMD_SHIFT) -+#define PMD_MASK (~(PMD_SIZE - 1)) -+ -+#define PGDIR_SHIFT (PMD_SHIFT + (PAGESHIFT() + PMD_ORDER - 3)) -+#define PGDIR_SIZE (1UL << PGDIR_SHIFT) -+#define PGDIR_MASK (~(PGDIR_SIZE - 1)) -+ -+#define PTRS_PER_PTE (1UL << (PAGESHIFT() - 3)) -+#define PTRS_PER_PMD PTRS_PER_PTE -+#define PTRS_PER_PGD PTRS_PER_PTE -+#define USER_PTRS_PER_PGD ((TASK_SIZE64 / PGDIR_SIZE)?(TASK_SIZE64 / PGDIR_SIZE) : 1) -+ -+#define pte_index(addr) (((addr) >> PAGESHIFT()) & (PTRS_PER_PTE - 1)) -+#define pmd_index(addr) (((addr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1)) -+#define pgd_index(addr) (((addr) >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1)) -+ -+#define LOONGARCH64_CPU_RIXI (1UL << 23) /* CPU has TLB Read/eXec Inhibit */ -+ -+#define LOONGARCH64_EF_R0 0 -+#define LOONGARCH64_EF_RA 1 -+#define LOONGARCH64_EF_SP 3 -+#define LOONGARCH64_EF_FP 22 -+#define LOONGARCH64_EF_CSR_EPC 32 -+#define LOONGARCH64_EF_CSR_BADVADDR 33 -+#define LOONGARCH64_EF_CSR_CRMD 34 -+#define LOONGARCH64_EF_CSR_PRMD 35 -+#define LOONGARCH64_EF_CSR_EUEN 36 -+#define LOONGARCH64_EF_CSR_ECFG 37 -+#define LOONGARCH64_EF_CSR_ESTAT 38 -+ -+static struct machine_specific loongarch64_machine_specific = { 0 }; -+ -+/* -+ * Holds registers during the crash. -+ */ -+static struct loongarch64_pt_regs *panic_task_regs; -+ -+/* -+ * Check and print the flags on the page -+ */ -+static void -+check_page_flags(ulong pte) -+{ -+#define CHECK_PAGE_FLAG(flag) \ -+ if ((_PAGE_##flag) && (pte & _PAGE_##flag)) \ -+ fprintf(fp, "%s" #flag, others++ ? "|" : "") -+ -+ int others = 0; -+ fprintf(fp, "("); -+ -+ if (pte) { -+ CHECK_PAGE_FLAG(VALID); -+ CHECK_PAGE_FLAG(DIRTY); -+ CHECK_PAGE_FLAG(PLV); -+ -+ /* Determine whether it is a huge page format */ -+ if (pte & _PAGE_HGLOBAL) { -+ CHECK_PAGE_FLAG(HUGE); -+ CHECK_PAGE_FLAG(HGLOBAL); -+ } else { -+ CHECK_PAGE_FLAG(GLOBAL); -+ } -+ -+ CHECK_PAGE_FLAG(PRESENT); -+ CHECK_PAGE_FLAG(WRITE); -+ CHECK_PAGE_FLAG(PROTNONE); -+ CHECK_PAGE_FLAG(SPECIAL); -+ CHECK_PAGE_FLAG(NO_READ); -+ CHECK_PAGE_FLAG(NO_EXEC); -+ CHECK_PAGE_FLAG(RPLV); -+ } else { -+ fprintf(fp, "no mapping"); -+ } -+ -+ fprintf(fp, ")\n"); -+} -+ -+/* -+ * Translate a PTE, returning TRUE if the page is present. -+ * If a physaddr pointer is passed in, don't print anything. -+ */ -+static int -+loongarch64_translate_pte(ulong pte, void *physaddr, ulonglong unused) -+{ -+ char ptebuf[BUFSIZE]; -+ char physbuf[BUFSIZE]; -+ char buf1[BUFSIZE]; -+ char buf2[BUFSIZE]; -+ char buf3[BUFSIZE]; -+ char *arglist[MAXARGS]; -+ int page_present; -+ int c, len1, len2, len3; -+ ulong paddr; -+ -+ paddr = PTOB(pte >> _PFN_SHIFT); -+ page_present = !!(pte & _PAGE_PRESENT); -+ -+ if (physaddr) { -+ *(ulong *)physaddr = paddr; -+ return page_present; -+ } -+ -+ sprintf(ptebuf, "%lx", pte); -+ len1 = MAX(strlen(ptebuf), strlen("PTE")); -+ fprintf(fp, "%s ", mkstring(buf1, len1, CENTER | LJUST, "PTE")); -+ -+ if (!page_present) { -+ swap_location(pte, buf1); -+ if ((c = parse_line(buf1, arglist)) != 3) -+ error(FATAL, "cannot determine swap location\n"); -+ -+ len2 = MAX(strlen(arglist[0]), strlen("SWAP")); -+ len3 = MAX(strlen(arglist[2]), strlen("OFFSET")); -+ -+ fprintf(fp, "%s %s\n", -+ mkstring(buf2, len2, CENTER|LJUST, "SWAP"), -+ mkstring(buf3, len3, CENTER|LJUST, "OFFSET")); -+ -+ strcpy(buf2, arglist[0]); -+ strcpy(buf3, arglist[2]); -+ fprintf(fp, "%s %s %s\n", -+ mkstring(ptebuf, len1, CENTER|RJUST, NULL), -+ mkstring(buf2, len2, CENTER|RJUST, NULL), -+ mkstring(buf3, len3, CENTER|RJUST, NULL)); -+ return page_present; -+ } -+ -+ sprintf(physbuf, "%lx", paddr); -+ len2 = MAX(strlen(physbuf), strlen("PHYSICAL")); -+ fprintf(fp, "%s ", mkstring(buf1, len2, CENTER | LJUST, "PHYSICAL")); -+ -+ fprintf(fp, "FLAGS\n"); -+ fprintf(fp, "%s %s ", -+ mkstring(ptebuf, len1, CENTER | RJUST, NULL), -+ mkstring(physbuf, len2, CENTER | RJUST, NULL)); -+ -+ check_page_flags(pte); -+ -+ return page_present; -+} -+ -+/* -+ * Identify and print the segment name to which the virtual address belongs -+ */ -+static void -+get_segment_name(ulong vaddr, int verbose) -+{ -+ const char * segment; -+ -+ if (verbose) { -+ if (vaddr < 0x4000000000000000lu) -+ segment = "xuvrange"; -+ else if (vaddr < 0x8000000000000000lu) -+ segment = "xsprange"; -+ else if (vaddr < 0xc000000000000000lu) -+ segment = "xkprange"; -+ else -+ segment = "xkvrange"; -+ -+ fprintf(fp, "SEGMENT: %s\n", segment); -+ } -+} -+ -+/* -+ * Virtual to physical memory translation. This function will be called -+ * by both loongarch64_kvtop and loongarch64_uvtop. -+ */ -+static int -+loongarch64_pgd_vtop(ulong *pgd, ulong vaddr, physaddr_t *paddr, int verbose) -+{ -+ ulong *pgd_ptr, pgd_val; -+ ulong *pmd_ptr, pmd_val; -+ ulong *pte_ptr, pte_val; -+ -+ get_segment_name(vaddr, verbose); -+ -+ if (IS_XKPRANGE(vaddr)) { -+ *paddr = VTOP(vaddr); -+ return TRUE; -+ } -+ -+ if (verbose) -+ fprintf(fp, "PAGE DIRECTORY: %016lx\n", (ulong)pgd); -+ -+ pgd_ptr = pgd + pgd_index(vaddr); -+ FILL_PGD(PAGEBASE(pgd), KVADDR, PAGESIZE()); -+ pgd_val = ULONG(machdep->pgd + PAGEOFFSET(pgd_ptr)); -+ if (verbose) -+ fprintf(fp, " PGD: %16lx => %16lx\n", (ulong)pgd_ptr, pgd_val); -+ if (!pgd_val) -+ goto no_page; -+ -+ pmd_ptr = (ulong *)(VTOP(pgd_val) + sizeof(pmd_t) * pmd_index(vaddr)); -+ FILL_PMD(PAGEBASE(pmd_ptr), PHYSADDR, PAGESIZE()); -+ pmd_val = ULONG(machdep->pmd + PAGEOFFSET(pmd_ptr)); -+ if (verbose) -+ fprintf(fp, " PMD: %016lx => %016lx\n", (ulong)pmd_ptr, pmd_val); -+ if (!pmd_val) -+ goto no_page; -+ -+ pte_ptr = (ulong *)(VTOP(pmd_val) + sizeof(pte_t) * pte_index(vaddr)); -+ FILL_PTBL(PAGEBASE(pte_ptr), PHYSADDR, PAGESIZE()); -+ pte_val = ULONG(machdep->ptbl + PAGEOFFSET(pte_ptr)); -+ if (verbose) -+ fprintf(fp, " PTE: %016lx => %016lx\n", (ulong)pte_ptr, pte_val); -+ if (!pte_val) -+ goto no_page; -+ -+ if (!(pte_val & _PAGE_PRESENT)) { -+ if (verbose) { -+ fprintf(fp, "\n"); -+ loongarch64_translate_pte((ulong)pte_val, 0, pte_val); -+ } -+ return FALSE; -+ } -+ -+ *paddr = PTOB(pte_val >> _PFN_SHIFT) + PAGEOFFSET(vaddr); -+ -+ if (verbose) { -+ fprintf(fp, " PAGE: %016lx\n\n", PAGEBASE(*paddr)); -+ loongarch64_translate_pte(pte_val, 0, 0); -+ } -+ -+ return TRUE; -+no_page: -+ fprintf(fp, "invalid\n"); -+ return FALSE; -+} -+ -+/* Translates a user virtual address to its physical address. cmd_vtop() sets -+ * the verbose flag so that the pte translation gets displayed; all other -+ * callers quietly accept the translation. -+ */ -+static int -+loongarch64_uvtop(struct task_context *tc, ulong vaddr, physaddr_t *paddr, int verbose) -+{ -+ ulong mm, active_mm; -+ ulong *pgd; -+ -+ if (!tc) -+ error(FATAL, "current context invalid\n"); -+ -+ *paddr = 0; -+ -+ if (is_kernel_thread(tc->task) && IS_KVADDR(vaddr)) { -+ readmem(tc->task + OFFSET(task_struct_active_mm), -+ KVADDR, &active_mm, sizeof(void *), -+ "task active_mm contents", FAULT_ON_ERROR); -+ -+ if (!active_mm) -+ error(FATAL, -+ "no active_mm for this kernel thread\n"); -+ -+ readmem(active_mm + OFFSET(mm_struct_pgd), -+ KVADDR, &pgd, sizeof(long), -+ "mm_struct pgd", FAULT_ON_ERROR); -+ } else { -+ if ((mm = task_mm(tc->task, TRUE))) -+ pgd = ULONG_PTR(tt->mm_struct + OFFSET(mm_struct_pgd)); -+ else -+ readmem(tc->mm_struct + OFFSET(mm_struct_pgd), -+ KVADDR, &pgd, sizeof(long), "mm_struct pgd", -+ FAULT_ON_ERROR); -+ } -+ -+ return loongarch64_pgd_vtop(pgd, vaddr, paddr, verbose);; -+} -+ -+/* Translates a user virtual address to its physical address. cmd_vtop() sets -+ * the verbose flag so that the pte translation gets displayed; all other -+ * callers quietly accept the translation. -+ */ -+static int -+loongarch64_kvtop(struct task_context *tc, ulong kvaddr, physaddr_t *paddr, int verbose) -+{ -+ if (!IS_KVADDR(kvaddr)) -+ return FALSE; -+ -+ if (!verbose) { -+ if (IS_XKPRANGE(kvaddr)) { -+ *paddr = VTOP(kvaddr); -+ return TRUE; -+ } -+ } -+ -+ return loongarch64_pgd_vtop((ulong *)vt->kernel_pgd[0], kvaddr, paddr, -+ verbose); -+} -+ -+/* -+ * Machine dependent command. -+ */ -+static void -+loongarch64_cmd_mach(void) -+{ -+ int c; -+ -+ while ((c = getopt(argcnt, args, "cmo")) != EOF) { -+ switch (c) { -+ case 'c': -+ case 'm': -+ case 'o': -+ option_not_supported(c); -+ break; -+ default: -+ argerrs++; -+ break; -+ } -+ } -+ -+ if (argerrs) -+ cmd_usage(pc->curcmd, SYNOPSIS); -+ -+ loongarch64_display_machine_stats(); -+} -+ -+/* -+ * "mach" command output. -+ */ -+static void -+loongarch64_display_machine_stats(void) -+{ -+ struct new_utsname *uts; -+ char buf[BUFSIZE]; -+ ulong mhz; -+ -+ uts = &kt->utsname; -+ -+ fprintf(fp, " MACHINE TYPE: %s\n", uts->machine); -+ fprintf(fp, " MEMORY SIZE: %s\n", get_memory_size(buf)); -+ fprintf(fp, " CPUS: %d\n", get_cpus_to_display()); -+ fprintf(fp, " PROCESSOR SPEED: "); -+ if ((mhz = machdep->processor_speed())) -+ fprintf(fp, "%ld Mhz\n", mhz); -+ else -+ fprintf(fp, "(unknown)\n"); -+ fprintf(fp, " HZ: %d\n", machdep->hz); -+ fprintf(fp, " PAGE SIZE: %d\n", PAGESIZE()); -+ fprintf(fp, " KERNEL STACK SIZE: %ld\n", STACKSIZE()); -+ -+} -+ -+/* -+ * Unroll a kernel stack. -+ */ -+static void -+loongarch64_back_trace_cmd(struct bt_info *bt) -+{ -+ struct loongarch64_unwind_frame current, previous; -+ struct loongarch64_pt_regs *regs; -+ char pt_regs[SIZE(pt_regs)]; -+ int level = 0; -+ int invalid_ok = 1; -+ -+ if (bt->flags & BT_REGS_NOT_FOUND) -+ return; -+ -+ previous.sp = previous.pc = previous.ra = 0; -+ -+ current.pc = bt->instptr; -+ current.sp = bt->stkptr; -+ current.ra = 0; -+ -+ if (!INSTACK(current.sp, bt)) -+ return; -+ -+ if (bt->machdep) { -+ regs = (struct loongarch64_pt_regs *)bt->machdep; -+ previous.pc = current.ra = regs->regs[LOONGARCH64_EF_RA]; -+ } -+ -+ while (current.sp <= bt->stacktop - 32 - SIZE(pt_regs)) { -+ struct syment *symbol = NULL; -+ ulong offset; -+ -+ if (CRASHDEBUG(8)) -+ fprintf(fp, "level %d pc %#lx ra %#lx sp %lx\n", -+ level, current.pc, current.ra, current.sp); -+ -+ if (!IS_KVADDR(current.pc) && !invalid_ok) -+ return; -+ -+ symbol = value_search(current.pc, &offset); -+ if (!symbol && !invalid_ok) { -+ error(FATAL, "PC is unknown symbol (%lx)", current.pc); -+ return; -+ } -+ invalid_ok = 0; -+ -+ /* -+ * If we get an address which points to the start of a -+ * function, then it could one of the following: -+ * -+ * - we are dealing with a noreturn function. The last call -+ * from a noreturn function has an ra which points to the -+ * start of the function after it. This is common in the -+ * oops callchain because of die() which is annotated as -+ * noreturn. -+ * -+ * - we have taken an exception at the start of this function. -+ * In this case we already have the RA in current.ra. -+ * -+ * - we are in one of these routines which appear with zero -+ * offset in manually-constructed stack frames: -+ * -+ * * ret_from_exception -+ * * ret_from_irq -+ * * ret_from_fork -+ * * ret_from_kernel_thread -+ */ -+ if (symbol && !STRNEQ(symbol->name, "ret_from") && !offset && -+ !current.ra && current.sp < bt->stacktop - 32 - SIZE(pt_regs)) { -+ if (CRASHDEBUG(8)) -+ fprintf(fp, "zero offset at %s, try previous symbol\n", -+ symbol->name); -+ -+ symbol = value_search(current.pc - 4, &offset); -+ if (!symbol) { -+ error(FATAL, "PC is unknown symbol (%lx)", current.pc); -+ return; -+ } -+ } -+ -+ if (symbol && loongarch64_is_exception_entry(symbol)) { -+ -+ GET_STACK_DATA(current.sp, pt_regs, sizeof(pt_regs)); -+ -+ previous.ra = regs->regs[LOONGARCH64_EF_RA]; -+ previous.sp = regs->regs[LOONGARCH64_EF_SP]; -+ current.ra = regs->csr_epc; -+ -+ if (CRASHDEBUG(8)) -+ fprintf(fp, "exception pc %#lx ra %#lx sp %lx\n", -+ previous.pc, previous.ra, previous.sp); -+ -+ /* The PC causing the exception may have been invalid */ -+ invalid_ok = 1; -+ } else if (symbol) { -+ loongarch64_analyze_function(symbol->value, offset, ¤t, &previous); -+ } else { -+ /* -+ * The current PC is invalid. Assume that the code -+ * jumped through a invalid pointer and that the SP has -+ * not been adjusted. -+ */ -+ previous.sp = current.sp; -+ } -+ -+ if (symbol) -+ loongarch64_dump_backtrace_entry(bt, symbol, ¤t, &previous, level++); -+ -+ current.pc = current.ra; -+ current.sp = previous.sp; -+ current.ra = previous.ra; -+ -+ if (CRASHDEBUG(8)) -+ fprintf(fp, "next %d pc %#lx ra %#lx sp %lx\n", -+ level, current.pc, current.ra, current.sp); -+ -+ previous.sp = previous.pc = previous.ra = 0; -+ } -+} -+ -+static void -+loongarch64_analyze_function(ulong start, ulong offset, -+ struct loongarch64_unwind_frame *current, -+ struct loongarch64_unwind_frame *previous) -+{ -+ ulong i, reg; -+ ulong rapos = 0; -+ ulong spadjust = 0; -+ uint32_t *funcbuf, *ip; -+ -+ if (CRASHDEBUG(8)) -+ fprintf(fp, "%s: start %#lx offset %#lx\n", -+ __func__, start, offset); -+ -+ if (!offset) { -+ previous->sp = current->sp; -+ return; -+ } -+ -+ ip = funcbuf = (uint32_t *)GETBUF(offset); -+ if (!readmem(start, KVADDR, funcbuf, offset, -+ "loongarch64_analyze_function", RETURN_ON_ERROR)) { -+ FREEBUF(funcbuf); -+ error(WARNING, "Cannot read function at %16lx\n", start); -+ return; -+ } -+ -+ for (i = 0; i < offset; i += 4) { -+ ulong insn = *ip & 0xffffffff; -+ ulong si12 = (insn >> 10) & 0xfff; /* bit[10:21] */ -+ -+ if (CRASHDEBUG(8)) -+ fprintf(fp, "insn @ %#lx = %#lx\n", start + i, insn); -+ -+ if ((insn & 0xffc003ff) == 0x02800063 || /* addi.w sp,sp,si12 */ -+ (insn & 0xffc003ff) == 0x02c00063) { /* addi.d sp,sp,si12 */ -+ if (!(si12 & 0x800)) /* si12 < 0 */ -+ break; -+ spadjust += 0x1000 - si12; -+ if (CRASHDEBUG(8)) -+ fprintf(fp, "si12 =%lu ,spadjust = %lu\n", si12, spadjust); -+ } else if ((insn & 0xffc003ff) == 0x29800061 || /* st.w ra,sp,si12 */ -+ (insn & 0xffc003ff) == 0x29c00061) { /* st.d ra,sp,si12 */ -+ rapos = current->sp + si12; -+ if (CRASHDEBUG(8)) -+ fprintf(fp, "rapos %lx\n", rapos); -+ break; -+ } -+ -+ ip++; -+ } -+ -+ FREEBUF(funcbuf); -+ -+ previous->sp = current->sp + spadjust; -+ -+ if (rapos && !readmem(rapos, KVADDR, ¤t->ra, -+ sizeof(current->ra), "RA from stack", -+ RETURN_ON_ERROR)) { -+ error(FATAL, "Cannot read RA from stack %lx", rapos); -+ return; -+ } -+} -+ -+static void -+loongarch64_dump_backtrace_entry(struct bt_info *bt, struct syment *sym, -+ struct loongarch64_unwind_frame *current, -+ struct loongarch64_unwind_frame *previous, int level) -+{ -+ const char *name = sym ? sym->name : "(invalid)"; -+ struct load_module *lm; -+ char *name_plus_offset = NULL; -+ struct syment *symp; -+ ulong symbol_offset; -+ char buf[BUFSIZE]; -+ char pt_regs[SIZE(pt_regs)]; -+ -+ if (bt->flags & BT_SYMBOL_OFFSET) { -+ symp = value_search(current->pc, &symbol_offset); -+ -+ if (symp && symbol_offset) -+ name_plus_offset = -+ value_to_symstr(current->pc, buf, bt->radix); -+ } -+ -+ fprintf(fp, "%s#%d [%016lx] %s at %016lx", level < 10 ? " " : "", level, -+ current->sp, name_plus_offset ? name_plus_offset : name, -+ current->pc); -+ -+ if (module_symbol(current->pc, NULL, &lm, NULL, 0)) -+ fprintf(fp, " [%s]", lm->mod_name); -+ -+ fprintf(fp, "\n"); -+ -+ /* -+ * 'bt -l', get a line number associated with a current pc address. -+ */ -+ if (bt->flags & BT_LINE_NUMBERS) { -+ get_line_number(current->pc, buf, FALSE); -+ if (strlen(buf)) -+ fprintf(fp, " %s\n", buf); -+ } -+ -+ if (sym && loongarch64_is_exception_entry(sym)) { -+ GET_STACK_DATA(current->sp, &pt_regs, SIZE(pt_regs)); -+ loongarch64_dump_exception_stack(bt, pt_regs); -+ } -+ -+ /* bt -f */ -+ if (bt->flags & BT_FULL) { -+ fprintf(fp, " " -+ "[PC: %016lx RA: %016lx SP: %016lx SIZE: %ld]\n", -+ current->pc, current->ra, current->sp, -+ previous->sp - current->sp); -+ loongarch64_display_full_frame(bt, current, previous); -+ } -+} -+ -+static void -+loongarch64_dump_exception_stack(struct bt_info *bt, char *pt_regs) -+{ -+ struct loongarch64_pt_regs *regs; -+ int i; -+ char buf[BUFSIZE]; -+ -+ for (i = 0; i < 32; i += 4) { -+ fprintf(fp, " $%2d : %016lx %016lx %016lx %016lx\n", -+ i, regs->regs[i], regs->regs[i+1], -+ regs->regs[i+2], regs->regs[i+3]); -+ } -+ -+ value_to_symstr(regs->csr_epc, buf, 16); -+ fprintf(fp, " epc : %016lx %s\n", regs->csr_epc, buf); -+ -+ value_to_symstr(regs->regs[LOONGARCH64_EF_RA], buf, 16); -+ fprintf(fp, " ra : %016lx %s\n", regs->regs[LOONGARCH64_EF_RA], buf); -+ -+ fprintf(fp, " CSR crmd : %016lx\n", regs->csr_crmd); -+ fprintf(fp, " CSR prmd : %016lx\n", regs->csr_prmd); -+ fprintf(fp, " CSR ecfg : %016lx\n", regs->csr_ecfg); -+ fprintf(fp, " CSR estat: %016lx\n", regs->csr_estat); -+ fprintf(fp, " CSR euen : %016lx\n", regs->csr_euen); -+ -+ fprintf(fp, " BadVA : %016lx\n", regs->csr_badvaddr); -+} -+ -+static int -+loongarch64_is_exception_entry(struct syment *sym) -+{ -+ return STREQ(sym->name, "ret_from_exception") || -+ STREQ(sym->name, "ret_from_irq") || -+ STREQ(sym->name, "work_resched") || -+ STREQ(sym->name, "handle_sys"); -+} -+ -+/* -+ * 'bt -f' commend output -+ * Display all stack data contained in a frame -+ */ -+static void -+loongarch64_display_full_frame(struct bt_info *bt, struct loongarch64_unwind_frame *current, -+ struct loongarch64_unwind_frame *previous) -+{ -+ int i, u_idx; -+ ulong *up; -+ ulong words, addr; -+ char buf[BUFSIZE]; -+ -+ if (previous->sp < current->sp) -+ return; -+ -+ if (!(INSTACK(previous->sp, bt) && INSTACK(current->sp, bt))) -+ return; -+ -+ words = (previous->sp - current->sp) / sizeof(ulong) + 1; -+ addr = current->sp; -+ u_idx = (current->sp - bt->stackbase) / sizeof(ulong); -+ -+ for (i = 0; i < words; i++, u_idx++) { -+ if (!(i & 1)) -+ fprintf(fp, "%s %lx: ", i ? "\n" : "", addr); -+ -+ up = (ulong *)(&bt->stackbuf[u_idx*sizeof(ulong)]); -+ fprintf(fp, "%s ", format_stack_entry(bt, buf, *up, 0)); -+ addr += sizeof(ulong); -+ } -+ fprintf(fp, "\n"); -+} -+ -+static void -+loongarch64_stackframe_init(void) -+{ -+ long task_struct_thread = MEMBER_OFFSET("task_struct", "thread"); -+ long thread_reg03_sp = MEMBER_OFFSET("thread_struct", "reg03"); -+ long thread_reg01_ra = MEMBER_OFFSET("thread_struct", "reg01"); -+ -+ if ((task_struct_thread == INVALID_OFFSET) || -+ (thread_reg03_sp == INVALID_OFFSET) || -+ (thread_reg01_ra == INVALID_OFFSET)) { -+ error(FATAL, -+ "cannot determine thread_struct offsets\n"); -+ return; -+ } -+ -+ ASSIGN_OFFSET(task_struct_thread_reg03) = -+ task_struct_thread + thread_reg03_sp; -+ ASSIGN_OFFSET(task_struct_thread_reg01) = -+ task_struct_thread + thread_reg01_ra; -+ -+ MEMBER_OFFSET_INIT(elf_prstatus_pr_reg, "elf_prstatus", "pr_reg"); -+ STRUCT_SIZE_INIT(note_buf, "note_buf_t"); -+} -+ -+/* -+ * Get a stack frame combination of pc and ra from the most relevant spot. -+ */ -+static void -+loongarch64_get_stack_frame(struct bt_info *bt, ulong *pcp, ulong *spp) -+{ -+ ulong ksp, nip; -+ int ret = 0; -+ -+ nip = ksp = 0; -+ bt->machdep = NULL; -+ -+ if (DUMPFILE() && is_task_active(bt->task)) { -+ ret = loongarch64_get_dumpfile_stack_frame(bt, &nip, &ksp); -+ } -+ else { -+ ret = loongarch64_get_frame(bt, &nip, &ksp); -+ } -+ -+ if (!ret) -+ error(WARNING, "cannot determine starting stack frame for task %lx\n", -+ bt->task); -+ -+ if (pcp) -+ *pcp = nip; -+ if (spp) -+ *spp = ksp; -+} -+ -+/* -+ * Get the starting point for the active cpu in a diskdump. -+ */ -+static int -+loongarch64_get_dumpfile_stack_frame(struct bt_info *bt, ulong *nip, ulong *ksp) -+{ -+ const struct machine_specific *ms = machdep->machspec; -+ struct loongarch64_pt_regs *regs; -+ ulong epc, sp; -+ -+ if (!ms->crash_task_regs) { -+ bt->flags |= BT_REGS_NOT_FOUND; -+ return FALSE; -+ } -+ -+ /* -+ * We got registers for panic task from crash_notes. Just return them. -+ */ -+ regs = &ms->crash_task_regs[bt->tc->processor]; -+ epc = regs->regs[LOONGARCH64_EF_CSR_EPC]; -+ sp = regs->regs[LOONGARCH64_EF_SP]; -+ -+ if (!epc && !sp) { -+ bt->flags |= BT_REGS_NOT_FOUND; -+ return FALSE; -+ } -+ -+ if (nip) -+ *nip = epc; -+ if (ksp) -+ *ksp = sp; -+ -+ bt->machdep = regs; -+ -+ return TRUE; -+} -+ -+/* -+ * Do the work for loongarch64_get_stack_frame() for non-active tasks. -+ * Get SP and PC values for idle tasks. -+ */ -+static int -+loongarch64_get_frame(struct bt_info *bt, ulong *pcp, ulong *spp) -+{ -+ if (!bt->tc || !(tt->flags & THREAD_INFO)) -+ return FALSE; -+ -+ if (!readmem(bt->task + OFFSET(task_struct_thread_reg01), -+ KVADDR, pcp, sizeof(*pcp), -+ "thread_struct.regs01", -+ RETURN_ON_ERROR)) { -+ return FALSE; -+ } -+ -+ if (!readmem(bt->task + OFFSET(task_struct_thread_reg03), -+ KVADDR, spp, sizeof(*spp), -+ "thread_struct.regs03", -+ RETURN_ON_ERROR)) { -+ return FALSE; -+ } -+ -+ return TRUE; -+} -+ -+static int -+loongarch64_init_active_task_regs(void) -+{ -+ int retval; -+ -+ retval = loongarch64_get_crash_notes(); -+ if (retval == TRUE) -+ return retval; -+ -+ return loongarch64_get_elf_notes(); -+} -+ -+/* -+ * Retrieve task registers for the time of the crash. -+ */ -+static int -+loongarch64_get_crash_notes(void) -+{ -+ struct machine_specific *ms = machdep->machspec; -+ ulong crash_notes; -+ Elf64_Nhdr *note; -+ ulong offset; -+ char *buf, *p; -+ ulong *notes_ptrs; -+ ulong i; -+ -+ /* -+ * crash_notes contains per cpu memory for storing cpu states -+ * in case of system crash. -+ */ -+ if (!symbol_exists("crash_notes")) -+ return FALSE; -+ -+ crash_notes = symbol_value("crash_notes"); -+ -+ notes_ptrs = (ulong *)GETBUF(kt->cpus*sizeof(notes_ptrs[0])); -+ -+ /* -+ * Read crash_notes for the first CPU. crash_notes are in standard ELF -+ * note format. -+ */ -+ if (!readmem(crash_notes, KVADDR, ¬es_ptrs[kt->cpus-1], -+ sizeof(notes_ptrs[kt->cpus-1]), "crash_notes", -+ RETURN_ON_ERROR)) { -+ error(WARNING, "cannot read crash_notes\n"); -+ FREEBUF(notes_ptrs); -+ return FALSE; -+ } -+ -+ if (symbol_exists("__per_cpu_offset")) { -+ -+ /* -+ * Add __per_cpu_offset for each cpu to form the pointer to the notes -+ */ -+ for (i = 0; i < kt->cpus; i++) -+ notes_ptrs[i] = notes_ptrs[kt->cpus-1] + kt->__per_cpu_offset[i]; -+ } -+ -+ buf = GETBUF(SIZE(note_buf)); -+ -+ if (!(panic_task_regs = calloc((size_t)kt->cpus, sizeof(*panic_task_regs)))) -+ error(FATAL, "cannot calloc panic_task_regs space\n"); -+ -+ for (i = 0; i < kt->cpus; i++) { -+ -+ if (!readmem(notes_ptrs[i], KVADDR, buf, SIZE(note_buf), "note_buf_t", -+ RETURN_ON_ERROR)) { -+ error(WARNING, -+ "cannot find NT_PRSTATUS note for cpu: %d\n", i); -+ goto fail; -+ } -+ -+ /* -+ * Do some sanity checks for this note before reading registers from it. -+ */ -+ note = (Elf64_Nhdr *)buf; -+ p = buf + sizeof(Elf64_Nhdr); -+ -+ /* -+ * dumpfiles created with qemu won't have crash_notes, but there will -+ * be elf notes; dumpfiles created by kdump do not create notes for -+ * offline cpus. -+ */ -+ if (note->n_namesz == 0 && (DISKDUMP_DUMPFILE() || KDUMP_DUMPFILE())) { -+ if (DISKDUMP_DUMPFILE()) -+ note = diskdump_get_prstatus_percpu(i); -+ else if (KDUMP_DUMPFILE()) -+ note = netdump_get_prstatus_percpu(i); -+ if (note) { -+ /* -+ * SIZE(note_buf) accounts for a "final note", which is a -+ * trailing empty elf note header. -+ */ -+ long notesz = SIZE(note_buf) - sizeof(Elf64_Nhdr); -+ -+ if (sizeof(Elf64_Nhdr) + roundup(note->n_namesz, 4) + -+ note->n_descsz == notesz) -+ BCOPY((char *)note, buf, notesz); -+ } else { -+ error(WARNING, -+ "cannot find NT_PRSTATUS note for cpu: %d\n", i); -+ continue; -+ } -+ } -+ -+ /* -+ * Check the sanity of NT_PRSTATUS note only for each online cpu. -+ */ -+ if (note->n_type != NT_PRSTATUS) { -+ error(WARNING, "invalid NT_PRSTATUS note (n_type != NT_PRSTATUS)\n"); -+ goto fail; -+ } -+ if (!STRNEQ(p, "CORE")) { -+ error(WARNING, "invalid NT_PRSTATUS note (name != \"CORE\"\n"); -+ goto fail; -+ } -+ -+ /* -+ * Find correct location of note data. This contains elf_prstatus -+ * structure which has registers etc. for the crashed task. -+ */ -+ offset = sizeof(Elf64_Nhdr); -+ offset = roundup(offset + note->n_namesz, 4); -+ p = buf + offset; /* start of elf_prstatus */ -+ -+ BCOPY(p + OFFSET(elf_prstatus_pr_reg), &panic_task_regs[i], -+ sizeof(panic_task_regs[i])); -+ } -+ -+ /* -+ * And finally we have the registers for the crashed task. This is -+ * used later on when dumping backtrace. -+ */ -+ ms->crash_task_regs = panic_task_regs; -+ -+ FREEBUF(buf); -+ FREEBUF(notes_ptrs); -+ return TRUE; -+ -+fail: -+ FREEBUF(buf); -+ FREEBUF(notes_ptrs); -+ free(panic_task_regs); -+ return FALSE; -+} -+ -+static int -+loongarch64_get_elf_notes(void) -+{ -+ struct machine_specific *ms = machdep->machspec; -+ int i; -+ -+ if (!DISKDUMP_DUMPFILE() && !KDUMP_DUMPFILE()) -+ return FALSE; -+ -+ panic_task_regs = calloc(kt->cpus, sizeof(*panic_task_regs)); -+ if (!panic_task_regs) -+ error(FATAL, "cannot calloc panic_task_regs space\n"); -+ -+ for (i = 0; i < kt->cpus; i++) { -+ Elf64_Nhdr *note = NULL; -+ size_t len; -+ -+ if (DISKDUMP_DUMPFILE()) -+ note = diskdump_get_prstatus_percpu(i); -+ else if (KDUMP_DUMPFILE()) -+ note = netdump_get_prstatus_percpu(i); -+ -+ if (!note) { -+ error(WARNING, -+ "cannot find NT_PRSTATUS note for cpu: %d\n", i); -+ continue; -+ } -+ -+ len = sizeof(Elf64_Nhdr); -+ len = roundup(len + note->n_namesz, 4); -+ -+ BCOPY((char *)note + len + OFFSET(elf_prstatus_pr_reg), -+ &panic_task_regs[i], sizeof(panic_task_regs[i])); -+ } -+ -+ ms->crash_task_regs = panic_task_regs; -+ -+ return TRUE; -+} -+ -+/* -+ * Accept or reject a symbol from the kernel namelist. -+ */ -+static int -+loongarch64_verify_symbol(const char *name, ulong value, char type) -+{ -+ if (CRASHDEBUG(8) && name && strlen(name)) -+ fprintf(fp, "%08lx %s\n", value, name); -+ -+ if (STREQ(name, "_text") || STREQ(name, "_stext")) -+ machdep->flags |= KSYMS_START; -+ -+ return (name && strlen(name) && (machdep->flags & KSYMS_START) && -+ !STRNEQ(name, "__func__.") && !STRNEQ(name, "__crc_")); -+} -+ -+/* -+ * Override smp_num_cpus if possible and necessary. -+ */ -+static int -+loongarch64_get_smp_cpus(void) -+{ -+ return (get_cpus_online() > 0) ? get_cpus_online() : kt->cpus; -+} -+ -+static ulong -+loongarch64_get_page_size(void) -+{ -+ return memory_page_size(); -+} -+ -+/* -+ * Determine where vmalloc'd memory starts. -+ */ -+static ulong -+loongarch64_vmalloc_start(void) -+{ -+ return first_vmalloc_address(); -+} -+ -+/* -+ * Calculate and return the speed of the processor. -+ */ -+static ulong -+loongarch64_processor_speed(void) -+{ -+ unsigned long cpu_hz = 0; -+ -+ if (machdep->mhz) -+ return (machdep->mhz); -+ -+ if (symbol_exists("cpu_clock_freq")) { -+ get_symbol_data("cpu_clock_freq", sizeof(int), &cpu_hz); -+ if (cpu_hz) -+ return(machdep->mhz = cpu_hz/1000000); -+ } -+ -+ return 0; -+} -+ -+/* -+ * Checks whether given task is valid task address. -+ */ -+static int -+loongarch64_is_task_addr(ulong task) -+{ -+ if (tt->flags & THREAD_INFO) -+ return IS_KVADDR(task); -+ -+ return (IS_KVADDR(task) && ALIGNED_STACK_OFFSET(task) == 0); -+} -+ -+/* -+ * 'help -m/M' command output -+ */ -+void -+loongarch64_dump_machdep_table(ulong arg) -+{ -+ int others = 0; -+ -+ fprintf(fp, " flags: %lx (", machdep->flags); -+ if (machdep->flags & KSYMS_START) -+ fprintf(fp, "%sKSYMS_START", others++ ? "|" : ""); -+ fprintf(fp, ")\n"); -+ -+ fprintf(fp, " kvbase: %lx\n", machdep->kvbase); -+ fprintf(fp, " identity_map_base: %lx\n", machdep->identity_map_base); -+ fprintf(fp, " pagesize: %d\n", machdep->pagesize); -+ fprintf(fp, " pageshift: %d\n", machdep->pageshift); -+ fprintf(fp, " pagemask: %llx\n", machdep->pagemask); -+ fprintf(fp, " pageoffset: %lx\n", machdep->pageoffset); -+ fprintf(fp, " pgdir_shift: %d\n", PGDIR_SHIFT); -+ fprintf(fp, " ptrs_per_pgd: %lu\n", PTRS_PER_PGD); -+ fprintf(fp, " ptrs_per_pte: %ld\n", PTRS_PER_PTE); -+ fprintf(fp, " stacksize: %ld\n", machdep->stacksize); -+ fprintf(fp, " hz: %d\n", machdep->hz); -+ fprintf(fp, " memsize: %ld (0x%lx)\n", -+ machdep->memsize, machdep->memsize); -+ fprintf(fp, " bits: %d\n", machdep->bits); -+ fprintf(fp, " back_trace: loongarch64_back_trace_cmd()\n"); -+ fprintf(fp, " processor_speed: loongarch64_processor_speed()\n"); -+ fprintf(fp, " uvtop: loongarch64_uvtop()\n"); -+ fprintf(fp, " kvtop: loongarch64_kvtop()\n"); -+ fprintf(fp, " get_stack_frame: loongarch64_get_stack_frame()\n"); -+ fprintf(fp, " get_stackbase: generic_get_stackbase()\n"); -+ fprintf(fp, " get_stacktop: generic_get_stacktop()\n"); -+ fprintf(fp, " translate_pte: loongarch64_translate_pte()\n"); -+ fprintf(fp, " memory_size: generic_memory_size()\n"); -+ fprintf(fp, " vmalloc_start: loongarch64_vmalloc_start()\n"); -+ fprintf(fp, " is_task_addr: loongarch64_is_task_addr()\n"); -+ fprintf(fp, " verify_symbol: loongarch64_verify_symbol()\n"); -+ fprintf(fp, " dis_filter: generic_dis_filter()\n"); -+ fprintf(fp, " dump_irq: generic_dump_irq()\n"); -+ fprintf(fp, " show_interrupts: generic_show_interrupts()\n"); -+ fprintf(fp, " get_irq_affinity: generic_get_irq_affinity()\n"); -+ fprintf(fp, " cmd_mach: loongarch64_cmd_mach()\n"); -+ fprintf(fp, " get_smp_cpus: loongarch64_get_smp_cpus()\n"); -+ fprintf(fp, " is_kvaddr: generic_is_kvaddr()\n"); -+ fprintf(fp, " is_uvaddr: generic_is_uvaddr()\n"); -+ fprintf(fp, " verify_paddr: generic_verify_paddr()\n"); -+ fprintf(fp, " init_kernel_pgd: NULL\n"); -+ fprintf(fp, " value_to_symbol: generic_machdep_value_to_symbol()\n"); -+ fprintf(fp, " line_number_hooks: NULL\n"); -+ fprintf(fp, " last_pgd_read: %lx\n", machdep->last_pgd_read); -+ fprintf(fp, " last_pmd_read: %lx\n", machdep->last_pmd_read); -+ fprintf(fp, " last_ptbl_read: %lx\n", machdep->last_ptbl_read); -+ fprintf(fp, " pgd: %lx\n", (ulong)machdep->pgd); -+ fprintf(fp, " pmd: %lx\n", (ulong)machdep->pmd); -+ fprintf(fp, " ptbl: %lx\n", (ulong)machdep->ptbl); -+ fprintf(fp, " section_size_bits: %ld\n", machdep->section_size_bits); -+ fprintf(fp, " max_physmem_bits: %ld\n", machdep->max_physmem_bits); -+ fprintf(fp, " sections_per_root: %ld\n", machdep->sections_per_root); -+ fprintf(fp, " machspec: %lx\n", (ulong)machdep->machspec); -+} -+ -+static void -+pt_level_alloc(char **lvl, char *name) -+{ -+ size_t sz = PAGESIZE(); -+ void *pointer = malloc(sz); -+ -+ if (!pointer) -+ error(FATAL, name); -+ *lvl = pointer; -+} -+ -+void -+loongarch64_init(int when) -+{ -+ switch (when) { -+ case SETUP_ENV: -+ machdep->process_elf_notes = process_elf64_notes; -+ break; -+ -+ case PRE_SYMTAB: -+ machdep->verify_symbol = loongarch64_verify_symbol; -+ machdep->machspec = &loongarch64_machine_specific; -+ if (pc->flags & KERNEL_DEBUG_QUERY) -+ return; -+ machdep->last_pgd_read = 0; -+ machdep->last_pmd_read = 0; -+ machdep->last_ptbl_read = 0; -+ machdep->verify_paddr = generic_verify_paddr; -+ machdep->ptrs_per_pgd = PTRS_PER_PGD; -+ break; -+ -+ case PRE_GDB: -+ machdep->pagesize = loongarch64_get_page_size(); -+ machdep->pageshift = ffs(machdep->pagesize) - 1; -+ machdep->pageoffset = machdep->pagesize - 1; -+ machdep->pagemask = ~((ulonglong)machdep->pageoffset); -+ if (machdep->pagesize >= 16384) -+ machdep->stacksize = machdep->pagesize; -+ else -+ machdep->stacksize = machdep->pagesize * 2; -+ -+ pt_level_alloc(&machdep->pgd, "cannot malloc pgd space."); -+ pt_level_alloc(&machdep->pmd, "cannot malloc pmd space."); -+ pt_level_alloc(&machdep->ptbl, "cannot malloc ptbl space."); -+ machdep->kvbase = 0x8000000000000000lu; -+ machdep->identity_map_base = machdep->kvbase; -+ machdep->is_kvaddr = generic_is_kvaddr; -+ machdep->is_uvaddr = generic_is_uvaddr; -+ machdep->uvtop = loongarch64_uvtop; -+ machdep->kvtop = loongarch64_kvtop; -+ machdep->cmd_mach = loongarch64_cmd_mach; -+ machdep->back_trace = loongarch64_back_trace_cmd; -+ machdep->get_stack_frame = loongarch64_get_stack_frame; -+ machdep->vmalloc_start = loongarch64_vmalloc_start; -+ machdep->processor_speed = loongarch64_processor_speed; -+ machdep->get_stackbase = generic_get_stackbase; -+ machdep->get_stacktop = generic_get_stacktop; -+ machdep->translate_pte = loongarch64_translate_pte; -+ machdep->memory_size = generic_memory_size; -+ machdep->is_task_addr = loongarch64_is_task_addr; -+ machdep->get_smp_cpus = loongarch64_get_smp_cpus; -+ machdep->dis_filter = generic_dis_filter; -+ machdep->dump_irq = generic_dump_irq; -+ machdep->show_interrupts = generic_show_interrupts; -+ machdep->get_irq_affinity = generic_get_irq_affinity; -+ machdep->value_to_symbol = generic_machdep_value_to_symbol; -+ machdep->init_kernel_pgd = NULL; -+ break; -+ -+ case POST_GDB: -+ machdep->section_size_bits = _SECTION_SIZE_BITS; -+ machdep->max_physmem_bits = _MAX_PHYSMEM_BITS; -+ -+ if (symbol_exists("irq_desc")) -+ ARRAY_LENGTH_INIT(machdep->nr_irqs, irq_desc, -+ "irq_desc", NULL, 0); -+ else if (kernel_symbol_exists("nr_irqs")) -+ get_symbol_data("nr_irqs", sizeof(unsigned int), -+ &machdep->nr_irqs); -+ -+ loongarch64_stackframe_init(); -+ -+ if (!machdep->hz) -+ machdep->hz = 250; -+ break; -+ -+ case POST_VM: -+ /* -+ * crash_notes contains machine specific information about the -+ * crash. In particular, it contains CPU registers at the time -+ * of the crash. We need this information to extract correct -+ * backtraces from the panic task. -+ */ -+ if (!ACTIVE() && !loongarch64_init_active_task_regs()) -+ error(WARNING,"cannot retrieve registers for active task%s\n\n", -+ kt->cpus > 1 ? "s" : ""); -+ break; -+ } -+} -+ -+void -+loongarch64_display_regs_from_elf_notes(int cpu, FILE *ofp) -+{ -+ const struct machine_specific *ms = machdep->machspec; -+ struct loongarch64_pt_regs *regs; -+ -+ if (!ms->crash_task_regs) { -+ error(INFO, "registers not collected for cpu %d\n", cpu); -+ return; -+ } -+ -+ regs = &ms->crash_task_regs[cpu]; -+ if (!regs->regs[LOONGARCH64_EF_SP] && !regs->regs[LOONGARCH64_EF_CSR_EPC]) { -+ error(INFO, "registers not collected for cpu %d\n", cpu); -+ return; -+ } -+ -+ fprintf(ofp, -+ " R0: %016lx R1: %016lx R2: %016lx\n" -+ " R3: %016lx R4: %016lx R5: %016lx\n" -+ " R6: %016lx R7: %016lx R8: %016lx\n" -+ " R9: %016lx R10: %016lx R11: %016lx\n" -+ " R12: %016lx R13: %016lx R14: %016lx\n" -+ " R15: %016lx R16: %016lx R17: %016lx\n" -+ " R18: %016lx R19: %016lx R20: %016lx\n" -+ " R21: %016lx R22: %016lx R23: %016lx\n" -+ " R24: %016lx R25: %016lx R26: %016lx\n" -+ " R27: %016lx R28: %016lx R29: %016lx\n" -+ " R30: %016lx R31: %016lx\n" -+ " CSR epc : %016lx CSR badv: %016lx\n" -+ " CSR crmd: %08lx CSR prmd: %08lx\n" -+ " CSR ecfg: %08lx CSR estat: %08lx\n" -+ " CSR eneu: %08lx", -+ regs->regs[LOONGARCH64_EF_R0], -+ regs->regs[LOONGARCH64_EF_R0 + 1], -+ regs->regs[LOONGARCH64_EF_R0 + 2], -+ regs->regs[LOONGARCH64_EF_R0 + 3], -+ regs->regs[LOONGARCH64_EF_R0 + 4], -+ regs->regs[LOONGARCH64_EF_R0 + 5], -+ regs->regs[LOONGARCH64_EF_R0 + 6], -+ regs->regs[LOONGARCH64_EF_R0 + 7], -+ regs->regs[LOONGARCH64_EF_R0 + 8], -+ regs->regs[LOONGARCH64_EF_R0 + 9], -+ regs->regs[LOONGARCH64_EF_R0 + 10], -+ regs->regs[LOONGARCH64_EF_R0 + 11], -+ regs->regs[LOONGARCH64_EF_R0 + 12], -+ regs->regs[LOONGARCH64_EF_R0 + 13], -+ regs->regs[LOONGARCH64_EF_R0 + 14], -+ regs->regs[LOONGARCH64_EF_R0 + 15], -+ regs->regs[LOONGARCH64_EF_R0 + 16], -+ regs->regs[LOONGARCH64_EF_R0 + 17], -+ regs->regs[LOONGARCH64_EF_R0 + 18], -+ regs->regs[LOONGARCH64_EF_R0 + 19], -+ regs->regs[LOONGARCH64_EF_R0 + 20], -+ regs->regs[LOONGARCH64_EF_R0 + 21], -+ regs->regs[LOONGARCH64_EF_R0 + 22], -+ regs->regs[LOONGARCH64_EF_R0 + 23], -+ regs->regs[LOONGARCH64_EF_R0 + 24], -+ regs->regs[LOONGARCH64_EF_R0 + 25], -+ regs->regs[LOONGARCH64_EF_R0 + 26], -+ regs->regs[LOONGARCH64_EF_R0 + 27], -+ regs->regs[LOONGARCH64_EF_R0 + 28], -+ regs->regs[LOONGARCH64_EF_R0 + 29], -+ regs->regs[LOONGARCH64_EF_R0 + 30], -+ regs->regs[LOONGARCH64_EF_R0 + 31], -+ regs->regs[LOONGARCH64_EF_CSR_EPC], -+ regs->regs[LOONGARCH64_EF_CSR_BADVADDR], -+ regs->regs[LOONGARCH64_EF_CSR_CRMD], -+ regs->regs[LOONGARCH64_EF_CSR_PRMD], -+ regs->regs[LOONGARCH64_EF_CSR_ECFG], -+ regs->regs[LOONGARCH64_EF_CSR_ESTAT], -+ regs->regs[LOONGARCH64_EF_CSR_EUEN]); -+} -+ -+#else /* !LOONGARCH64 */ -+ -+#include "defs.h" -+ -+void -+loongarch64_display_regs_from_elf_notes(int cpu, FILE *ofp) -+{ -+ return; -+} -+ -+#endif /* !LOONGARCH64 */ -diff --git a/main.c b/main.c -index dfd343c..b278c22 100644 ---- a/main.c -+++ b/main.c -@@ -1704,7 +1704,6 @@ dump_program_context(void) - fprintf(fp, " gdb_sigaction: %lx\n", (ulong)&pc->gdb_sigaction); - fprintf(fp, " main_loop_env: %lx\n", (ulong)&pc->main_loop_env); - fprintf(fp, " foreach_loop_env: %lx\n", (ulong)&pc->foreach_loop_env); -- fprintf(fp, "gdb_interface_env: %lx\n", (ulong)&pc->gdb_interface_env); - fprintf(fp, " termios_orig: %lx\n", (ulong)&pc->termios_orig); - fprintf(fp, " termios_raw: %lx\n", (ulong)&pc->termios_raw); - fprintf(fp, " ncmds: %d\n", pc->ncmds); -diff --git a/netdump.c b/netdump.c -index e8721d8..116282b 100644 ---- a/netdump.c -+++ b/netdump.c -@@ -42,6 +42,7 @@ static void get_netdump_regs_ppc64(struct bt_info *, ulong *, ulong *); - static void get_netdump_regs_arm(struct bt_info *, ulong *, ulong *); - static void get_netdump_regs_arm64(struct bt_info *, ulong *, ulong *); - static void get_netdump_regs_mips(struct bt_info *, ulong *, ulong *); -+static void get_netdump_regs_loongarch64(struct bt_info *, ulong *, ulong *); - static void check_dumpfile_size(char *); - static int proc_kcore_init_32(FILE *, int); - static int proc_kcore_init_64(FILE *, int); -@@ -300,6 +301,12 @@ is_netdump(char *file, ulong source_query) - goto bailout; - break; - -+ case EM_LOONGARCH: -+ if (machine_type_mismatch(file, "LOONGARCH64", NULL, -+ source_query)) -+ goto bailout; -+ break; -+ - default: - if (machine_type_mismatch(file, "(unknown)", NULL, - source_query)) -@@ -1482,6 +1489,9 @@ dump_Elf32_Ehdr(Elf32_Ehdr *elf) - case EM_MIPS: - netdump_print("(EM_MIPS)\n"); - break; -+ case EM_LOONGARCH: -+ netdump_print("(EM_LOONGARCH)\n"); -+ break; - default: - netdump_print("(unsupported)\n"); - break; -@@ -1644,6 +1654,9 @@ dump_Elf64_Ehdr(Elf64_Ehdr *elf) - case EM_AARCH64: - netdump_print("(EM_AARCH64)\n"); - break; -+ case EM_LOONGARCH: -+ netdump_print("(EM_LOONGARCH)\n"); -+ break; - default: - netdump_print("(unsupported)\n"); - break; -@@ -2669,6 +2682,10 @@ get_netdump_regs(struct bt_info *bt, ulong *eip, ulong *esp) - return get_netdump_regs_mips(bt, eip, esp); - break; - -+ case EM_LOONGARCH: -+ return get_netdump_regs_loongarch64(bt, eip, esp); -+ break; -+ - default: - error(FATAL, - "support for ELF machine type %d not available\n", -@@ -2925,6 +2942,8 @@ display_regs_from_elf_notes(int cpu, FILE *ofp) - mips_display_regs_from_elf_notes(cpu, ofp); - } else if (machine_type("MIPS64")) { - mips64_display_regs_from_elf_notes(cpu, ofp); -+ } else if (machine_type("LOONGARCH64")) { -+ loongarch64_display_regs_from_elf_notes(cpu, ofp); - } - } - -@@ -2935,7 +2954,8 @@ dump_registers_for_elf_dumpfiles(void) - - if (!(machine_type("X86") || machine_type("X86_64") || - machine_type("ARM64") || machine_type("PPC64") || -- machine_type("MIPS") || machine_type("MIPS64"))) -+ machine_type("MIPS") || machine_type("MIPS64") || -+ machine_type("LOONGARCH64"))) - error(FATAL, "-r option not supported for this dumpfile\n"); - - if (NETDUMP_DUMPFILE()) { -@@ -3870,6 +3890,12 @@ get_netdump_regs_mips(struct bt_info *bt, ulong *eip, ulong *esp) - machdep->get_stack_frame(bt, eip, esp); - } - -+static void -+get_netdump_regs_loongarch64(struct bt_info *bt, ulong *eip, ulong *esp) -+{ -+ machdep->get_stack_frame(bt, eip, esp); -+} -+ - int - is_partial_netdump(void) - { -@@ -5206,11 +5232,17 @@ kdump_kaslr_check(void) - return FALSE; - } - --#ifdef X86_64 - int - kdump_get_nr_cpus(void) - { -- return nd->num_qemu_notes; -+ if (nd->num_prstatus_notes) -+ return nd->num_prstatus_notes; -+ else if (nd->num_qemu_notes) -+ return nd->num_qemu_notes; -+ else if (nd->num_vmcoredd_notes) -+ return nd->num_vmcoredd_notes; -+ -+ return 1; - } - - QEMUCPUState * -@@ -5232,7 +5264,6 @@ kdump_get_qemucpustate(int cpu) - - return (QEMUCPUState *)nd->nt_qemu_percpu[cpu]; - } --#endif - - static void * - get_kdump_device_dump_offset(void) -diff --git a/ramdump.c b/ramdump.c -index a206fcb..c32d9fd 100644 ---- a/ramdump.c -+++ b/ramdump.c -@@ -188,6 +188,8 @@ char *ramdump_to_elf(void) - e_machine = EM_MIPS; - else if (machine_type("X86_64")) - e_machine = EM_X86_64; -+ else if (machine_type("LOONGARCH64")) -+ e_machine = EM_LOONGARCH; - else - error(FATAL, "ramdump: unsupported machine type: %s\n", - MACHINE_TYPE); -diff --git a/sadump.c b/sadump.c -index d75c66b..cb43fdb 100644 ---- a/sadump.c -+++ b/sadump.c -@@ -1670,7 +1670,6 @@ get_sadump_data(void) - return sd; - } - --#ifdef X86_64 - int - sadump_get_nr_cpus(void) - { -@@ -1678,6 +1677,7 @@ sadump_get_nr_cpus(void) - return sd->dump_header->nr_cpus; - } - -+#ifdef X86_64 - int - sadump_get_cr3_cr4_idtr(int cpu, ulong *cr3, ulong *cr4, ulong *idtr) - { -diff --git a/symbols.c b/symbols.c -index 1cad240..752be46 100644 ---- a/symbols.c -+++ b/symbols.c -@@ -17,7 +17,7 @@ - - #include "defs.h" - #include --#ifdef GDB_7_6 -+#if defined(GDB_7_6) || defined(GDB_8_1) - #define __CONFIG_H__ 1 - #include "config.h" - #endif -@@ -34,7 +34,7 @@ static int compare_mods(const void *, const void *); - static int compare_prios(const void *v1, const void *v2); - static int compare_size_name(const void *, const void *); - struct type_request; --static void append_struct_symbol (struct type_request *, struct gnu_request *); -+static void append_struct_symbol (struct gnu_request *, void *); - static void request_types(ulong, ulong, char *); - static asection *get_kernel_section(char *); - static char * get_section(ulong vaddr, char *buf); -@@ -443,7 +443,7 @@ separate_debug_file_exists(const char *name, unsigned long crc, int *exists) - #ifdef GDB_5_3 - file_crc = calc_crc32(file_crc, buffer, count); - #else --#ifdef GDB_7_6 -+#if defined(GDB_7_6) || defined(GDB_8_1) - file_crc = bfd_calc_gnu_debuglink_crc32(file_crc, - (unsigned char *)buffer, count); - #else -@@ -524,9 +524,9 @@ get_text_init_space(void) - return; - } - -- kt->stext_init = (ulong)bfd_get_section_vma(st->bfd, section); -- kt->etext_init = kt->stext_init + -- (ulong)bfd_section_size(st->bfd, section); -+ kt->stext_init = (ulong)bfd_section_vma(st->bfd, section); -+ kt->etext_init = kt->stext_init + -+ (ulong)bfd_section_size(st->bfd, section); - - if (kt->relocate) { - kt->stext_init -= kt->relocate; -@@ -774,7 +774,6 @@ store_symbols(bfd *abfd, int dynamic, void *minisyms, long symcount, - - bfd_get_symbol_info(abfd, sym, &syminfo); - name = strip_symbol_end(syminfo.name, buf); -- - if (machdep->verify_symbol(name, syminfo.value, - syminfo.type)) { - if (kt->flags & (RELOC_SET|RELOC_FORCE)) -@@ -2955,10 +2954,8 @@ is_kernel_text(ulong value) - for (i = 0; i < st->bfd->section_count; i++, sec++) { - section = *sec; - if (section->flags & SEC_CODE) { -- start = (ulong)bfd_get_section_vma(st->bfd, -- section); -- end = start + (ulong)bfd_section_size(st->bfd, -- section); -+ start = (ulong)bfd_section_vma(st->bfd, section); -+ end = start + (ulong)bfd_section_size(st->bfd, section); - - if (kt->flags2 & KASLR) { - start += (kt->relocate * -1); -@@ -3574,7 +3571,7 @@ dump_symbol_table(void) - section = *sec; - fprintf(fp, "%25s vma: %.*lx size: %ld\n", - section->name, VADDR_PRLEN, -- (ulong)bfd_get_section_vma(st->bfd, section), -+ (ulong)bfd_section_vma(st->bfd, section), - (ulong)bfd_section_size(st->bfd, section)); - } - fprintf(fp, "\n downsized: "); -@@ -3696,6 +3693,11 @@ is_kernel(char *file) - goto bailout; - break; - -+ case EM_LOONGARCH: -+ if (machine_type_mismatch(file, "LOONGARCH64", NULL, 0)) -+ goto bailout; -+ break; -+ - default: - if (machine_type_mismatch(file, "(unknown)", NULL, 0)) - goto bailout; -@@ -4004,6 +4006,11 @@ is_shared_object(char *file) - if (machine_type("MIPS64")) - return TRUE; - break; -+ -+ case EM_LOONGARCH: -+ if (machine_type("LOONGARCH64")) -+ return TRUE; -+ break; - } - - if (CRASHDEBUG(1)) -@@ -4467,12 +4474,11 @@ get_section(ulong vaddr, char *buf) - sec = (asection **)st->sections; - for (i = 0; i < st->bfd->section_count; i++, sec++) { - section = *sec; -- start = (ulong)bfd_get_section_vma(st->bfd, section); -+ start = (ulong)bfd_section_vma(st->bfd, section); - end = start + (ulong)bfd_section_size(st->bfd, section); - - if ((vaddr >= start) && (vaddr < end)) { -- strcpy(buf, bfd_get_section_name(st->bfd, -- section)); -+ strcpy(buf, bfd_section_name(st->bfd, section)); - break; - } - } -@@ -7053,13 +7059,14 @@ compare_size_name(const void *va, const void *vb) { - } - - static void --append_struct_symbol (struct type_request *treq, struct gnu_request *req) -+append_struct_symbol (struct gnu_request *req, void *data) - { -+ struct type_request *treq = (struct type_request *)data; - int i; - long s; - - for (i = 0; i < treq->idx; i++) -- if (treq->types[i].name == req->name) -+ if (!strcmp(treq->types[i].name, req->name)) - break; - - if (i < treq->idx) // We've already collected this type -@@ -7094,22 +7101,13 @@ request_types(ulong lowest, ulong highest, char *member_name) - request.type_name = member_name; - #endif - -- while (!request.global_iterator.finished) { -- request.command = GNU_GET_NEXT_DATATYPE; -- gdb_interface(&request); -- if (highest && -- !(lowest <= request.length && request.length <= highest)) -- continue; -- -- if (member_name) { -- request.command = GNU_LOOKUP_STRUCT_CONTENTS; -- gdb_interface(&request); -- if (!request.value) -- continue; -- } -- -- append_struct_symbol(&typereq, &request); -- } -+ request.command = GNU_ITERATE_DATATYPES; -+ request.lowest = lowest; -+ request.highest = highest; -+ request.member = member_name; -+ request.callback = append_struct_symbol; -+ request.callback_data = (void *)&typereq; -+ gdb_interface(&request); - - qsort(typereq.types, typereq.idx, sizeof(struct type_info), compare_size_name); - -@@ -8830,6 +8828,10 @@ dump_offset_table(char *spec, ulong makestruct) - OFFSET(task_struct_thread_esp)); - fprintf(fp, " task_struct_thread_ksp: %ld\n", - OFFSET(task_struct_thread_ksp)); -+ fprintf(fp, " task_struct_thread_reg01: %ld\n", -+ OFFSET(task_struct_thread_reg01)); -+ fprintf(fp, " task_struct_thread_reg03: %ld\n", -+ OFFSET(task_struct_thread_reg03)); - fprintf(fp, " task_struct_thread_reg29: %ld\n", - OFFSET(task_struct_thread_reg29)); - fprintf(fp, " task_struct_thread_reg31: %ld\n", -@@ -11249,38 +11251,38 @@ section_header_info(bfd *bfd, asection *section, void *reqptr) - sec++; - *sec = section; - -- if (STREQ(bfd_get_section_name(bfd, section), ".text.init") || -- STREQ(bfd_get_section_name(bfd, section), ".init.text")) { -+ if (STREQ(bfd_section_name(bfd, section), ".text.init") || -+ STREQ(bfd_section_name(bfd, section), ".init.text")) { - kt->stext_init = (ulong) -- bfd_get_section_vma(bfd, section); -+ bfd_section_vma(bfd, section); - kt->etext_init = kt->stext_init + -- (ulong)bfd_section_size(bfd, section); -+ (ulong)bfd_section_size(bfd, section); - } - -- if (STREQ(bfd_get_section_name(bfd, section), ".text")) { -+ if (STREQ(bfd_section_name(bfd, section), ".text")) { - st->first_section_start = (ulong) -- bfd_get_section_vma(bfd, section); -+ bfd_section_vma(bfd, section); - } -- if (STREQ(bfd_get_section_name(bfd, section), ".text") || -- STREQ(bfd_get_section_name(bfd, section), ".data")) { -+ if (STREQ(bfd_section_name(bfd, section), ".text") || -+ STREQ(bfd_section_name(bfd, section), ".data")) { - if (!(bfd_get_section_flags(bfd, section) & SEC_LOAD)) - st->flags |= NO_SEC_LOAD; - if (!(bfd_get_section_flags(bfd, section) & - SEC_HAS_CONTENTS)) - st->flags |= NO_SEC_CONTENTS; - } -- if (STREQ(bfd_get_section_name(bfd, section), ".eh_frame")) { -+ if (STREQ(bfd_section_name(bfd, section), ".eh_frame")) { - st->dwarf_eh_frame_file_offset = (off_t)section->filepos; - st->dwarf_eh_frame_size = (ulong)bfd_section_size(bfd, section); - } -- if (STREQ(bfd_get_section_name(bfd, section), ".debug_frame")) { -+ if (STREQ(bfd_section_name(bfd, section), ".debug_frame")) { - st->dwarf_debug_frame_file_offset = (off_t)section->filepos; - st->dwarf_debug_frame_size = (ulong)bfd_section_size(bfd, section); - } - - if (st->first_section_start != 0) { - section_end_address = -- (ulong) bfd_get_section_vma(bfd, section) + -+ (ulong) bfd_section_vma(bfd, section) + - (ulong) bfd_section_size(bfd, section); - if (section_end_address > st->last_section_end) - st->last_section_end = section_end_address; -@@ -11293,19 +11295,19 @@ section_header_info(bfd *bfd, asection *section, void *reqptr) - break; - - case (ulong)VERIFY_SECTIONS: -- if (STREQ(bfd_get_section_name(bfd, section), ".text") || -- STREQ(bfd_get_section_name(bfd, section), ".data")) { -+ if (STREQ(bfd_section_name(bfd, section), ".text") || -+ STREQ(bfd_section_name(bfd, section), ".data")) { - if (!(bfd_get_section_flags(bfd, section) & SEC_LOAD)) - st->flags |= NO_SEC_LOAD; -- if (!(bfd_get_section_flags(bfd, section) & -+ if (!(bfd_get_section_flags(bfd, section) & - SEC_HAS_CONTENTS)) - st->flags |= NO_SEC_CONTENTS; - } -- if (STREQ(bfd_get_section_name(bfd, section), ".eh_frame")) { -+ if (STREQ(bfd_section_name(bfd, section), ".eh_frame")) { - st->dwarf_eh_frame_file_offset = (off_t)section->filepos; - st->dwarf_eh_frame_size = (ulong)bfd_section_size(bfd, section); - } -- if (STREQ(bfd_get_section_name(bfd, section), ".debug_frame")) { -+ if (STREQ(bfd_section_name(bfd, section), ".debug_frame")) { - st->dwarf_debug_frame_file_offset = (off_t)section->filepos; - st->dwarf_debug_frame_size = (ulong)bfd_section_size(bfd, section); - } -@@ -11347,7 +11349,7 @@ store_section_data(struct load_module *lm, bfd *bfd, asection *section) - char *name; - - prio = 0; -- name = (char *)bfd_get_section_name(bfd, section); -+ name = (char *)bfd_section_name(bfd, section); - - if (name[0] != '.' || strlen(name) != 10 || strcmp(name + 5, ".init")) - prio |= 32; -@@ -11450,7 +11452,7 @@ calculate_load_order_v1(struct load_module *lm, bfd *bfd) - for (i = (lm->mod_sections-1); i >= 0; i--) { - section = lm->mod_section_data[i].section; - -- alignment = power(2, bfd_get_section_alignment(bfd, section)); -+ alignment = power(2, bfd_section_alignment(bfd, section)); - - if (alignment && (offset & (alignment - 1))) - offset = (offset | (alignment - 1)) + 1; -@@ -11481,7 +11483,7 @@ calculate_load_order_v1(struct load_module *lm, bfd *bfd) - - offset += bfd_section_size(bfd, section); - -- if (STREQ(bfd_get_section_name(bfd, section), ".kstrtab")) -+ if (STREQ(bfd_section_name(bfd, section), ".kstrtab")) - offset += strlen(lm->mod_name)+1; - } - } -@@ -11558,7 +11560,7 @@ calculate_load_order_v2(struct load_module *lm, bfd *bfd, int dynamic, - (long) syminfo.value); - } - if (strcmp(syminfo.name, s1->name) == 0) { -- secname = (char *)bfd_get_section_name(bfd, sym->section); -+ secname = (char *)bfd_section_name(bfd, sym->section); - break; - } - -@@ -12306,7 +12308,7 @@ store_load_module_symbols(bfd *bfd, int dynamic, void *minisyms, - - bfd_get_symbol_info(bfd, sym, &syminfo); - -- secname = (char *)bfd_get_section_name(bfd, sym->section); -+ secname = (char *)bfd_section_name(bfd, sym->section); - found = 0; - - if (kt->flags & KMOD_V1) { -@@ -12869,8 +12871,8 @@ numeric_forward(const void *P_x, const void *P_y) - st->saved_command_line_vmlinux = valueof(y); - } - -- xs = bfd_get_section(x); -- ys = bfd_get_section(y); -+ xs = bfd_get_section(x); -+ ys = bfd_get_section(y); - - if (bfd_is_und_section(xs)) { - if (!bfd_is_und_section(ys)) -diff --git a/tools.c b/tools.c -index 6fa3c70..39306c1 100644 ---- a/tools.c -+++ b/tools.c -@@ -6239,7 +6239,7 @@ drop_core(char *s) - * The first time it's called, the device will be opened. - */ - int --console(char *fmt, ...) -+console(const char *fmt, ...) - { - char output[BUFSIZE*2]; - va_list ap; -diff --git a/vmware_guestdump.c b/vmware_guestdump.c -index 62da0a7..b19b64c 100644 ---- a/vmware_guestdump.c -+++ b/vmware_guestdump.c -@@ -267,6 +267,11 @@ vmware_guestdump_init(char *filename, FILE *ofp) - fseek(vmss.dfp, 0L, SEEK_SET); - fprintf(ofp, LOGPRX"vmem file: %s\n\n", vmem_filename); - -+ if (CRASHDEBUG(1)) { -+ vmware_guestdump_memory_dump(ofp); -+ dump_registers_for_vmss_dump(); -+ } -+ - exit: - if (fp) - fclose(fp); -diff --git a/vmware_vmss.c b/vmware_vmss.c -index 52d58e8..1171218 100644 ---- a/vmware_vmss.c -+++ b/vmware_vmss.c -@@ -1,7 +1,7 @@ - /* - * vmware_vmss.c - * -- * Copyright (c) 2015 VMware, Inc. -+ * Copyright (c) 2015, 2020 VMware, Inc. - * Copyright (c) 2018 Red Hat Inc. - * - * This program is free software; you can redistribute it and/or modify -@@ -16,6 +16,7 @@ - * - * Authors: Dyno Hongjun Fu - * Sergio Lopez -+ * Alexey Makhalov - */ - - #include "defs.h" -@@ -443,11 +444,13 @@ vmware_vmss_init(char *filename, FILE *ofp) - if (vmss.memsize == 0) { - char *vmem_filename, *p; - -- fprintf(ofp, LOGPRX"Memory dump is not part of this vmss file.\n"); -+ if (!(pc->flags & SILENT)) -+ fprintf(ofp, LOGPRX"Memory dump is not part of this vmss file.\n"); - fclose(fp); - fp = NULL; - -- fprintf(ofp, LOGPRX"Try to locate the companion vmem file ...\n"); -+ if (!(pc->flags & SILENT)) -+ fprintf(ofp, LOGPRX"Try to locate the companion vmem file ...\n"); - /* check the companion vmem file */ - vmem_filename = strdup(filename); - p = vmem_filename + strlen(vmem_filename) - 4; -@@ -470,7 +473,8 @@ vmware_vmss_init(char *filename, FILE *ofp) - vmss.separate_vmem = TRUE; - vmss.filename = filename; - -- fprintf(ofp, LOGPRX"vmem file: %s\n\n", vmem_filename); -+ if (!(pc->flags & SILENT)) -+ fprintf(ofp, LOGPRX"vmem file: %s\n\n", vmem_filename); - free(vmem_filename); - } - -@@ -891,6 +895,54 @@ vmware_vmss_get_cr3_cr4_idtr(int cpu, ulong *cr3, ulong *cr4, ulong *idtr) - return TRUE; - } - -+int -+vmware_vmss_get_cpu_reg(int cpu, int regno, const char *name, int size, -+ void *value) -+{ -+ if (cpu >= vmss.num_vcpus) -+ return FALSE; -+ -+ /* All supported registers are 8 bytes long. */ -+ if (size != 8) -+ return FALSE; -+ -+#define CASE(R,r) \ -+ case R##_REGNUM: \ -+ if (!(vmss.vcpu_regs[cpu] & REGS_PRESENT_##R)) \ -+ return FALSE; \ -+ memcpy(value, &vmss.regs64[cpu]->r, size); \ -+ break -+ -+ -+ switch (regno) { -+ CASE (RAX, rax); -+ CASE (RBX, rbx); -+ CASE (RCX, rcx); -+ CASE (RDX, rdx); -+ CASE (RSI, rsi); -+ CASE (RDI, rdi); -+ CASE (RBP, rbp); -+ CASE (RSP, rsp); -+ CASE (R8, r8); -+ CASE (R9, r9); -+ CASE (R10, r10); -+ CASE (R11, r11); -+ CASE (R12, r12); -+ CASE (R13, r13); -+ CASE (R14, r14); -+ CASE (R15, r15); -+ CASE (RIP, rip); -+ case EFLAGS_REGNUM: -+ if (!(vmss.vcpu_regs[cpu] & REGS_PRESENT_RFLAGS)) -+ return FALSE; -+ memcpy(value, &vmss.regs64[cpu]->rflags, size); -+ break; -+ default: -+ return FALSE; -+ } -+ return TRUE; -+} -+ - int - vmware_vmss_phys_base(ulong *phys_base) - { -diff --git a/x86_64.c b/x86_64.c -index 87cbeae..3dec8e8 100644 ---- a/x86_64.c -+++ b/x86_64.c -@@ -126,6 +126,7 @@ static int x86_64_get_framesize(struct bt_info *, ulong, ulong); - static void x86_64_framesize_debug(struct bt_info *); - static void x86_64_get_active_set(void); - static int x86_64_get_kvaddr_ranges(struct vaddr_range *); -+static int x86_64_get_cpu_reg(int, int, const char *, int, void *); - static int x86_64_verify_paddr(uint64_t); - static void GART_init(void); - static void x86_64_exception_stacks_init(void); -@@ -194,6 +195,7 @@ x86_64_init(int when) - machdep->machspec->irq_eframe_link = UNINITIALIZED; - machdep->machspec->irq_stack_gap = UNINITIALIZED; - machdep->get_kvaddr_ranges = x86_64_get_kvaddr_ranges; -+ machdep->get_cpu_reg = x86_64_get_cpu_reg; - if (machdep->cmdline_args[0]) - parse_cmdline_args(); - if ((string = pc->read_vmcoreinfo("relocate"))) { -@@ -884,6 +886,7 @@ x86_64_dump_machdep_table(ulong arg) - fprintf(fp, " is_page_ptr: x86_64_is_page_ptr()\n"); - fprintf(fp, " verify_paddr: x86_64_verify_paddr()\n"); - fprintf(fp, " get_kvaddr_ranges: x86_64_get_kvaddr_ranges()\n"); -+ fprintf(fp, " get_cpu_reg: x86_64_get_cpu_reg()\n"); - fprintf(fp, " init_kernel_pgd: x86_64_init_kernel_pgd()\n"); - fprintf(fp, "clear_machdep_cache: x86_64_clear_machdep_cache()\n"); - fprintf(fp, " xendump_p2m_create: %s\n", PVOPS_XEN() ? -@@ -4415,7 +4418,7 @@ x86_64_function_called_by(ulong rip) - if (gdb_pass_through(buf, pc->tmpfile2, GNU_RETURN_ON_ERROR)) { - rewind(pc->tmpfile2); - while (fgets(buf, BUFSIZE, pc->tmpfile2)) { -- if ((p1 = strstr(buf, "callq")) && -+ if ((p1 = strstr(buf, "call")) && - whitespace(*(p1-1))) { - if (extract_hex(p1, &value, NULLCHAR, TRUE)) - break; -@@ -6381,11 +6384,13 @@ search_for_switch_to(ulong start, ulong end) - char search_string1[BUFSIZE]; - char search_string2[BUFSIZE]; - char search_string3[BUFSIZE]; -+ char search_string4[BUFSIZE]; - int found; - - max_instructions = end - start; - found = FALSE; -- search_string1[0] = search_string2[0] = search_string3[0] = NULLCHAR; -+ search_string1[0] = search_string2[0] = NULLCHAR; -+ search_string3[0] = search_string4[0] = NULLCHAR; - sprintf(buf1, "x/%ldi 0x%lx", max_instructions, start); - - if (symbol_exists("__switch_to")) { -@@ -6397,6 +6402,8 @@ search_for_switch_to(ulong start, ulong end) - if (symbol_exists("__switch_to_asm")) { - sprintf(search_string3, - "callq 0x%lx", symbol_value("__switch_to_asm")); -+ sprintf(search_string4, -+ "call 0x%lx", symbol_value("__switch_to_asm")); - } - - open_tmpfile(); -@@ -6416,6 +6423,8 @@ search_for_switch_to(ulong start, ulong end) - found = TRUE; - if (strlen(search_string3) && strstr(buf1, search_string3)) - found = TRUE; -+ if (strlen(search_string4) && strstr(buf1, search_string4)) -+ found = TRUE; - } - close_tmpfile(); - -@@ -7104,7 +7113,7 @@ x86_64_virt_phys_base(void) - ulong phys, linux_banner_phys; - - if (!(sp = symbol_search("linux_banner")) || -- !((sp->type == 'R') || (sp->type == 'r'))) -+ !((sp->type == 'R') || (sp->type == 'r') || (sp->type == 'D'))) - return FALSE; - - linux_banner_phys = sp->value - __START_KERNEL_map; -@@ -8229,7 +8238,7 @@ x86_64_do_not_cache_framesize(struct syment *sp, ulong textaddr) - return TRUE; - } - -- if (STREQ(arglist[instr], "callq")) -+ if (STREQ(arglist[instr], "callq") || STREQ(arglist[instr], "call")) - break; - } - close_tmpfile2(); -@@ -8927,6 +8936,19 @@ x86_64_get_kvaddr_ranges(struct vaddr_range *vrp) - return cnt; - } - -+static int -+x86_64_get_cpu_reg(int cpu, int regno, const char *name, -+ int size, void *value) -+{ -+ if (regno >= LAST_REGNUM) -+ return FALSE; -+ -+ if (VMSS_DUMPFILE()) -+ return vmware_vmss_get_cpu_reg(cpu, regno, name, size, value); -+ -+ return FALSE; -+} -+ - /* - * Determine the physical memory range reserved for GART. - */ --- -2.20.1 - diff --git a/0001-crash-add-loongarch-support.patch b/0001-crash-add-loongarch-support.patch new file mode 100644 index 0000000000000000000000000000000000000000..9ec6f3a40284e9d6b59f619455106176f10dcc67 --- /dev/null +++ b/0001-crash-add-loongarch-support.patch @@ -0,0 +1,16162 @@ +From 5e35316de0791db9a132a0d2d91659eceff70e2d Mon Sep 17 00:00:00 2001 +From: Liwei Ge +Date: Thu, 5 Jan 2023 21:24:30 +0800 +Subject: [PATCH] crash: add loongarch support + +--- + Makefile | 9 +- + README | 4 +- + configure.c | 27 +- + defs.h | 160 +- + diskdump.c | 26 +- + gdb-10.2-loongarch.patch | 14101 +++++++++++++++++++++++++++++++++++++ + gdb_interface.c | 1 - + lkcd_vmdump_v1.h | 2 + + lkcd_vmdump_v2_v3.h | 4 +- + loongarch64.c | 1344 ++++ + netdump.c | 28 +- + ramdump.c | 2 + + symbols.c | 14 + + 13 files changed, 15711 insertions(+), 11 deletions(-) + create mode 100644 gdb-10.2-loongarch.patch + create mode 100644 loongarch64.c + +diff --git a/Makefile b/Makefile +index a1e1639..5535651 100644 +--- a/Makefile ++++ b/Makefile +@@ -64,7 +64,7 @@ CFILES=main.c tools.c global_data.c memory.c filesys.c help.c task.c \ + kernel.c test.c gdb_interface.c configure.c net.c dev.c bpf.c \ + printk.c \ + alpha.c x86.c ppc.c ia64.c s390.c s390x.c s390dbf.c ppc64.c x86_64.c \ +- arm.c arm64.c mips.c mips64.c sparc64.c \ ++ arm.c arm64.c mips.c mips64.c sparc64.c loongarch64.c\ + extensions.c remote.c va_server.c va_server_v1.c symbols.c cmdline.c \ + lkcd_common.c lkcd_v1.c lkcd_v2_v3.c lkcd_v5.c lkcd_v7.c lkcd_v8.c\ + lkcd_fix_mem.c s390_dump.c lkcd_x86_trace.c \ +@@ -84,7 +84,7 @@ OBJECT_FILES=main.o tools.o global_data.o memory.o filesys.o help.o task.o \ + build_data.o kernel.o test.o gdb_interface.o net.o dev.o bpf.o \ + printk.o \ + alpha.o x86.o ppc.o ia64.o s390.o s390x.o s390dbf.o ppc64.o x86_64.o \ +- arm.o arm64.o mips.o mips64.o sparc64.o \ ++ arm.o arm64.o mips.o mips64.o sparc64.o loongarch64.o\ + extensions.o remote.o va_server.o va_server_v1.o symbols.o cmdline.o \ + lkcd_common.o lkcd_v1.o lkcd_v2_v3.o lkcd_v5.o lkcd_v7.o lkcd_v8.o \ + lkcd_fix_mem.o s390_dump.o netdump.o diskdump.o makedumpfile.o xendump.o \ +@@ -292,6 +292,8 @@ gdb_unzip: + gdb_patch: + if [ -f ${GDB}.patch ] && [ -s ${GDB}.patch ]; then \ + patch -p0 < ${GDB}.patch; cp ${GDB}.patch ${GDB}; fi ++ if [ -f ${GDB}-loongarch.patch ] && [ -s ${GDB}-loongarch.patch ]; then \ ++ patch -p0 < ${GDB}-loongarch.patch; cp ${GDB}-loongarch.patch ${GDB}; fi + + library: ${OBJECT_FILES} + ar -rs ${PROGRAM}lib.a ${OBJECT_FILES} +@@ -441,6 +443,9 @@ mips64.o: ${GENERIC_HFILES} ${REDHAT_HFILES} mips64.c + sparc64.o: ${GENERIC_HFILES} ${REDHAT_HFILES} sparc64.c + ${CC} -c ${CRASH_CFLAGS} sparc64.c ${WARNING_OPTIONS} ${WARNING_ERROR} + ++loongarch64.o: ${GENERIC_HFILES} ${REDHAT_HFILES} loongarch64.c ++ ${CC} -c ${CRASH_CFLAGS} loongarch64.c ${WARNING_OPTIONS} ${WARNING_ERROR} ++ + s390.o: ${GENERIC_HFILES} ${IBM_HFILES} s390.c + ${CC} -c ${CRASH_CFLAGS} s390.c ${WARNING_OPTIONS} ${WARNING_ERROR} + +diff --git a/README b/README +index 5abbce1..c2609ea 100644 +--- a/README ++++ b/README +@@ -37,8 +37,8 @@ + These are the current prerequisites: + + o At this point, x86, ia64, x86_64, ppc64, ppc, arm, arm64, alpha, mips, +- mips64, s390 and s390x-based kernels are supported. Other architectures +- may be addressed in the future. ++ mips64, loongarch64, s390 and s390x-based kernels are supported. Other ++ architectures may be addressed in the future. + + o One size fits all -- the utility can be run on any Linux kernel version + version dating back to 2.2.5-15. A primary design goal is to always +diff --git a/configure.c b/configure.c +index 1c24fdc..0813260 100644 +--- a/configure.c ++++ b/configure.c +@@ -107,6 +107,7 @@ void add_extra_lib(char *); + #undef MIPS + #undef SPARC64 + #undef MIPS64 ++#undef LOONGARCH64 + + #define UNKNOWN 0 + #define X86 1 +@@ -122,6 +123,7 @@ void add_extra_lib(char *); + #define MIPS 11 + #define SPARC64 12 + #define MIPS64 13 ++#define LOONGARCH64 14 + + #define TARGET_X86 "TARGET=X86" + #define TARGET_ALPHA "TARGET=ALPHA" +@@ -136,6 +138,7 @@ void add_extra_lib(char *); + #define TARGET_MIPS "TARGET=MIPS" + #define TARGET_MIPS64 "TARGET=MIPS64" + #define TARGET_SPARC64 "TARGET=SPARC64" ++#define TARGET_LOONGARCH64 "TARGET=LOONGARCH64" + + #define TARGET_CFLAGS_X86 "TARGET_CFLAGS=-D_FILE_OFFSET_BITS=64" + #define TARGET_CFLAGS_ALPHA "TARGET_CFLAGS=" +@@ -158,6 +161,7 @@ void add_extra_lib(char *); + #define TARGET_CFLAGS_MIPS_ON_X86_64 "TARGET_CFLAGS=-m32 -D_FILE_OFFSET_BITS=64" + #define TARGET_CFLAGS_MIPS64 "TARGET_CFLAGS=" + #define TARGET_CFLAGS_SPARC64 "TARGET_CFLAGS=" ++#define TARGET_CFLAGS_LOONGARCH64 "TARGET_CFLAGS=" + + #define GDB_TARGET_DEFAULT "GDB_CONF_FLAGS=" + #define GDB_TARGET_ARM_ON_X86 "GDB_CONF_FLAGS=--target=arm-elf-linux" +@@ -404,6 +408,9 @@ get_current_configuration(struct supported_gdb_version *sp) + #ifdef __sparc_v9__ + target_data.target = SPARC64; + #endif ++#ifdef __loongarch64 ++ target_data.target = LOONGARCH64; ++#endif + + set_initial_target(sp); + +@@ -497,6 +504,10 @@ get_current_configuration(struct supported_gdb_version *sp) + (target_data.target != MIPS64)) + arch_mismatch(sp); + ++ if ((target_data.initial_gdb_target == LOONGARCH64) && ++ (target_data.target != LOONGARCH64)) ++ arch_mismatch(sp); ++ + if ((target_data.initial_gdb_target == X86) && + (target_data.target != X86)) { + if (target_data.target == X86_64) +@@ -660,6 +671,9 @@ show_configuration(void) + case SPARC64: + printf("TARGET: SPARC64\n"); + break; ++ case LOONGARCH64: ++ printf("TARGET: LOONGARCH64\n"); ++ break; + } + + if (strlen(target_data.program)) { +@@ -777,6 +791,10 @@ build_configure(struct supported_gdb_version *sp) + target = TARGET_SPARC64; + target_CFLAGS = TARGET_CFLAGS_SPARC64; + break; ++ case LOONGARCH64: ++ target = TARGET_LOONGARCH64; ++ target_CFLAGS = TARGET_CFLAGS_LOONGARCH64; ++ break; + } + + ldflags = get_extra_flags("LDFLAGS.extra", NULL); +@@ -1375,7 +1393,7 @@ make_spec_file(struct supported_gdb_version *sp) + printf("Vendor: Red Hat, Inc.\n"); + printf("Packager: Dave Anderson \n"); + printf("ExclusiveOS: Linux\n"); +- printf("ExclusiveArch: %%{ix86} alpha ia64 ppc ppc64 ppc64pseries ppc64iseries x86_64 s390 s390x arm aarch64 ppc64le mips mipsel mips64el sparc64\n"); ++ printf("ExclusiveArch: %%{ix86} alpha ia64 ppc ppc64 ppc64pseries ppc64iseries x86_64 s390 s390x arm aarch64 ppc64le mips mipsel mips64el sparc64 loongarch64\n"); + printf("Buildroot: %%{_tmppath}/%%{name}-root\n"); + printf("BuildRequires: ncurses-devel zlib-devel bison\n"); + printf("Requires: binutils\n"); +@@ -1614,6 +1632,8 @@ set_initial_target(struct supported_gdb_version *sp) + target_data.initial_gdb_target = MIPS; + else if (strncmp(buf, "SPARC64", strlen("SPARC64")) == 0) + target_data.initial_gdb_target = SPARC64; ++ else if (strncmp(buf, "LOONGARCH64", strlen("LOONGARCH64")) == 0) ++ target_data.initial_gdb_target = LOONGARCH64; + } + + char * +@@ -1634,6 +1654,7 @@ target_to_name(int target) + case MIPS: return("MIPS"); + case MIPS64: return("MIPS64"); + case SPARC64: return("SPARC64"); ++ case LOONGARCH64: return("LOONGARCH64"); + } + + return "UNKNOWN"; +@@ -1698,6 +1719,10 @@ name_to_target(char *name) + return MIPS64; + else if (strncmp(name, "sparc64", strlen("sparc64")) == 0) + return SPARC64; ++ else if (strncmp(name, "loongarch64", strlen("loongarch64")) == 0) ++ return LOONGARCH64; ++ else if (strncmp(name, "LOONGARCH64", strlen("LOONGARCH64")) == 0) ++ return LOONGARCH64; + + return UNKNOWN; + } +diff --git a/defs.h b/defs.h +index 7d3b734..267cddc 100644 +--- a/defs.h ++++ b/defs.h +@@ -76,7 +76,7 @@ + #if !defined(X86) && !defined(X86_64) && !defined(ALPHA) && !defined(PPC) && \ + !defined(IA64) && !defined(PPC64) && !defined(S390) && !defined(S390X) && \ + !defined(ARM) && !defined(ARM64) && !defined(MIPS) && !defined(MIPS64) && \ +- !defined(SPARC64) ++ !defined(SPARC64) && !defined(LOONGARCH64) + #ifdef __alpha__ + #define ALPHA + #endif +@@ -118,6 +118,9 @@ + #ifdef __sparc_v9__ + #define SPARC64 + #endif ++#ifdef __loongarch64 ++#define LOONGARCH64 ++#endif + #endif + + #ifdef X86 +@@ -159,6 +162,9 @@ + #ifdef SPARC64 + #define NR_CPUS (4096) + #endif ++#ifdef LOONGARCH64 ++#define NR_CPUS (256) ++#endif + + #define NR_DEVICE_DUMPS (64) + +@@ -2005,6 +2011,8 @@ struct offset_table { /* stash of commonly-used offsets */ + long atomic_t_counter; + long percpu_counter_count; + long mm_struct_mm_count; ++ long task_struct_thread_reg01; ++ long task_struct_thread_reg03; + long task_struct_thread_reg29; + long task_struct_thread_reg31; + long pt_regs_regs; +@@ -3484,6 +3492,43 @@ struct arm64_stackframe { + #define _MAX_PHYSMEM_BITS 48 + #endif /* MIPS64 */ + ++#ifdef LOONGARCH64 ++#define _64BIT_ ++#define MACHINE_TYPE "LOONGARCH64" ++ ++#define PAGEBASE(X) (((ulong)(X)) & (ulong)machdep->pagemask) ++ ++#define IS_XKPRANGE(X) (((X) >= 0x8000000000000000lu) && \ ++ ((X) < 0xc000000000000000lu)) ++ ++#define PTOV(X) ((ulong)(X) + 0x9000000000000000lu) ++#define VTOP(X) ((ulong)(X) & 0x0000fffffffffffflu) ++ ++#define IS_VMALLOC_ADDR(X) (vt->vmalloc_start && (ulong)(X) >= vt->vmalloc_start) ++ ++#define DEFAULT_MODULES_VADDR 0xffff800000000000lu ++#define MODULES_VADDR (machdep->machspec->modules_vaddr) ++#define MODULES_END (machdep->machspec->modules_end) ++#define VMALLOC_START (machdep->machspec->vmalloc_start_addr) ++#define VMALLOC_END (machdep->machspec->vmalloc_end) ++ ++#define __SWP_TYPE_SHIFT 16 ++#define __SWP_TYPE_BITS 8 ++#define __SWP_TYPE_MASK ((1 << __SWP_TYPE_BITS) - 1) ++#define __SWP_OFFSET_SHIFT (__SWP_TYPE_BITS + __SWP_TYPE_SHIFT) ++ ++#define SWP_TYPE(entry) (((entry) >> __SWP_TYPE_SHIFT) & __SWP_TYPE_MASK) ++#define SWP_OFFSET(entry) ((entry) >> __SWP_OFFSET_SHIFT) ++ ++#define __swp_type(entry) SWP_TYPE(entry) ++#define __swp_offset(entry) SWP_OFFSET(entry) ++ ++#define TIF_SIGPENDING (1) ++ ++#define _SECTION_SIZE_BITS 28 ++#define _MAX_PHYSMEM_BITS 48 ++#endif /* LOONGARCH64 */ ++ + #ifdef X86 + #define _32BIT_ + #define MACHINE_TYPE "X86" +@@ -4532,6 +4577,10 @@ struct machine_specific { + #define MAX_HEXADDR_STRLEN (16) + #define UVADDR_PRLEN (16) + #endif ++#ifdef LOONGARCH64 ++#define MAX_HEXADDR_STRLEN (16) ++#define UVADDR_PRLEN (16) ++#endif + + #define BADADDR ((ulong)(-1)) + #define BADVAL ((ulong)(-1)) +@@ -5129,6 +5178,9 @@ void dump_build_data(void); + #ifdef SPARC64 + #define machdep_init(X) sparc64_init(X) + #endif ++#ifdef LOONGARCH64 ++#define machdep_init(X) loongarch64_init(X) ++#endif + int clean_exit(int); + int untrusted_file(FILE *, char *); + char *readmem_function_name(void); +@@ -5606,6 +5658,9 @@ void display_help_screen(char *); + #ifdef SPARC64 + #define dump_machdep_table(X) sparc64_dump_machdep_table(X) + #endif ++#ifdef LOONGARCH64 ++#define dump_machdep_table(X) loongarch64_dump_machdep_table(X) ++#endif + extern char *help_pointer[]; + extern char *help_alias[]; + extern char *help_ascii[]; +@@ -6681,6 +6736,109 @@ int sparc64_vmalloc_addr(ulong); + error(FATAL, "The -d option is not applicable to sparc64.\n") + #endif + ++/* ++ * loongarch64.c ++ */ ++void loongarch64_display_regs_from_elf_notes(int, FILE *); ++ ++#ifdef LOONGARCH64 ++void loongarch64_init(int); ++void loongarch64_dump_machdep_table(ulong); ++ ++#define display_idt_table() \ ++ error(FATAL, "-d option is not applicable to LOONGARCH64 architecture\n") ++ ++/* from arch/loongarch/include/asm/ptrace.h */ ++struct loongarch64_pt_regs { ++ /* Saved main processor registers. */ ++ unsigned long regs[32]; ++ ++ /* Saved special registers. */ ++ unsigned long csr_crmd; ++ unsigned long csr_prmd; ++ unsigned long csr_euen; ++ unsigned long csr_ecfg; ++ unsigned long csr_estat; ++ unsigned long csr_epc; ++ unsigned long csr_badvaddr; ++ unsigned long orig_a0; ++}; ++ ++struct loongarch64_unwind_frame { ++ unsigned long sp; ++ unsigned long pc; ++ unsigned long ra; ++}; ++ ++#define KSYMS_START (0x1) ++ ++struct machine_specific { ++ ulong phys_base; ++ ulong vmalloc_start_addr; ++ ulong modules_vaddr; ++ ulong modules_end; ++ ++ struct loongarch64_pt_regs *crash_task_regs; ++}; ++ ++/* ++ * Basic page table format: ++ * ++ * 63 62 61 PALEN-1 12 10 9 8 7 6 5 4 3 2 1 0 ++ * +----+--+--+------+--------------------+----+--+--+-+-+-+---+---+-+-+ ++ * |RPLV|NX|NR| | PA[PALEN-1:12] | |SP|PN|W|P|G|MAT|PLV|D|V| ++ * +----+--+--+------+--------------------+----+--+--+-+-+-+---+---+-+-+ ++ * ++ * ++ * Huge page table format: ++ * ++ * 63 62 61 PALEN-1 12 10 9 8 7 6 5 4 3 2 1 0 ++ * +----+--+--+------+-----------------+--+----+--+--+-+-+-+---+---+-+-+ ++ * |RPLV|NX|NR| | PA[PALEN-1:12] | G| |SP|PN|W|P|H|MAT|PLV|D|V| ++ * +----+--+--+------+-----------------+--+----+--+--+-+-+-+---+---+-+-+ ++ * ++ */ ++/* from arch/loongarch/include/asm/pgtable-bits.h */ ++ ++/* Page table bits */ ++#define _PAGE_VALID_SHIFT 0 ++#define _PAGE_DIRTY_SHIFT 1 ++#define _PAGE_PLV_SHIFT 2 /* 2~3, two bits */ ++#define _CACHE_SHIFT 4 /* 4~5, two bits */ ++#define _PAGE_GLOBAL_SHIFT 6 ++#define _PAGE_HUGE_SHIFT 6 /* HUGE is a PMD bit */ ++#define _PAGE_PRESENT_SHIFT 7 ++#define _PAGE_WRITE_SHIFT 8 ++#define _PAGE_PROTNONE_SHIFT 9 ++#define _PAGE_SPECIAL_SHIFT 10 ++#define _PAGE_HGLOBAL_SHIFT 12 /* HGlobal is a PMD bit */ ++#define _PAGE_PFN_SHIFT 12 ++#define _PAGE_PFN_END_SHIFT 48 ++#define _PAGE_NO_READ_SHIFT 61 ++#define _PAGE_NO_EXEC_SHIFT 62 ++#define _PAGE_RPLV_SHIFT 63 ++ ++/* Used only by software */ ++#define _PAGE_PRESENT (1UL << _PAGE_PRESENT_SHIFT) ++#define _PAGE_WRITE (1UL << _PAGE_WRITE_SHIFT) ++#define _PAGE_PROTNONE (1UL << _PAGE_PROTNONE_SHIFT) ++#define _PAGE_SPECIAL (1UL << _PAGE_SPECIAL_SHIFT) ++ ++/* Used by TLB hardware (placed in EntryLo*) */ ++#define _PAGE_VALID (1UL << _PAGE_VALID_SHIFT) ++#define _PAGE_DIRTY (1UL << _PAGE_DIRTY_SHIFT) ++#define _PAGE_PLV (3UL << _PAGE_PLV_SHIFT) ++#define _PAGE_GLOBAL (1UL << _PAGE_GLOBAL_SHIFT) ++#define _PAGE_HUGE (1UL << _PAGE_HUGE_SHIFT) ++#define _PAGE_HGLOBAL (1UL << _PAGE_HGLOBAL_SHIFT) ++#define _PAGE_NO_READ (1UL << _PAGE_NO_READ_SHIFT) ++#define _PAGE_NO_EXEC (1UL << _PAGE_NO_EXEC_SHIFT) ++#define _PAGE_RPLV (1UL << _PAGE_RPLV_SHIFT) ++#define _CACHE_MASK (3UL << _CACHE_SHIFT) ++#define _PFN_SHIFT (PAGESHIFT() - 12 + _PAGE_PFN_SHIFT) ++ ++#endif /* LOONGARCH64 */ ++ + /* + * netdump.c + */ +diff --git a/diskdump.c b/diskdump.c +index ac8ecbd..c8bcdb6 100644 +--- a/diskdump.c ++++ b/diskdump.c +@@ -625,6 +625,9 @@ restart: + else if (STRNEQ(header->utsname.machine, "aarch64") && + machine_type_mismatch(file, "ARM64", NULL, 0)) + goto err; ++ else if (STRNEQ(header->utsname.machine, "loongarch64") && ++ machine_type_mismatch(file, "LOONGARCH64", NULL, 0)) ++ goto err; + + if (header->block_size != block_size) { + block_size = header->block_size; +@@ -783,6 +786,8 @@ restart: + dd->machine_type = EM_AARCH64; + else if (machine_type("SPARC64")) + dd->machine_type = EM_SPARCV9; ++ else if (machine_type("LOONGARCH64")) ++ dd->machine_type = EM_LOONGARCH; + else { + error(INFO, "%s: unsupported machine type: %s\n", + DISKDUMP_VALID() ? "diskdump" : "compressed kdump", +@@ -1529,6 +1534,12 @@ get_diskdump_regs_mips(struct bt_info *bt, ulong *eip, ulong *esp) + machdep->get_stack_frame(bt, eip, esp); + } + ++static void ++get_diskdump_regs_loongarch64(struct bt_info *bt, ulong *eip, ulong *esp) ++{ ++ machdep->get_stack_frame(bt, eip, esp); ++} ++ + static void + get_diskdump_regs_sparc64(struct bt_info *bt, ulong *eip, ulong *esp) + { +@@ -1608,6 +1619,10 @@ get_diskdump_regs(struct bt_info *bt, ulong *eip, ulong *esp) + get_diskdump_regs_sparc64(bt, eip, esp); + break; + ++ case EM_LOONGARCH: ++ get_diskdump_regs_loongarch64(bt, eip, esp); ++ break; ++ + default: + error(FATAL, "%s: unsupported machine type: %s\n", + DISKDUMP_VALID() ? "diskdump" : "compressed kdump", +@@ -1754,7 +1769,8 @@ dump_note_offsets(FILE *fp) + qemu = FALSE; + if (machine_type("X86_64") || machine_type("S390X") || + machine_type("ARM64") || machine_type("PPC64") || +- machine_type("SPARC64") || machine_type("MIPS64")) { ++ machine_type("SPARC64") || machine_type("MIPS64") || ++ machine_type("LOONGARCH64")) { + note64 = (void *)dd->notes_buf + tot; + len = sizeof(Elf64_Nhdr); + if (STRNEQ((char *)note64 + len, "QEMU")) +@@ -1865,6 +1881,8 @@ __diskdump_memory_dump(FILE *fp) + fprintf(fp, "(EM_AARCH64)\n"); break; + case EM_SPARCV9: + fprintf(fp, "(EM_SPARCV9)\n"); break; ++ case EM_LOONGARCH: ++ fprintf(fp, "(EM_LOONGARCH)\n"); break; + default: + fprintf(fp, "(unknown)\n"); break; + } +@@ -2551,6 +2569,9 @@ diskdump_display_regs(int cpu, FILE *ofp) + + if (machine_type("MIPS64")) + mips64_display_regs_from_elf_notes(cpu, ofp); ++ ++ if (machine_type("LOONGARCH64")) ++ loongarch64_display_regs_from_elf_notes(cpu, ofp); + } + + void +@@ -2561,7 +2582,8 @@ dump_registers_for_compressed_kdump(void) + if (!KDUMP_CMPRS_VALID() || (dd->header->header_version < 4) || + !(machine_type("X86") || machine_type("X86_64") || + machine_type("ARM64") || machine_type("PPC64") || +- machine_type("MIPS") || machine_type("MIPS64"))) ++ machine_type("MIPS") || machine_type("MIPS64") || ++ machine_type("LOONGARCH64"))) + error(FATAL, "-r option not supported for this dumpfile\n"); + + if (machine_type("ARM64") && (kt->cpus != dd->num_prstatus_notes)) +diff --git a/gdb-10.2-loongarch.patch b/gdb-10.2-loongarch.patch +new file mode 100644 +index 0000000..4418bcb +--- /dev/null ++++ b/gdb-10.2-loongarch.patch +@@ -0,0 +1,14101 @@ ++From 287c80883d76368ec0220f490a437e034de25d4b Mon Sep 17 00:00:00 2001 ++From: Liwei Ge ++Date: Thu, 5 Jan 2023 18:27:07 +0800 ++Subject: [PATCH] gdb-10.2: add loongarch support ++ ++--- ++ bfd/Makefile.am | 17 + ++ bfd/Makefile.in | 23 + ++ bfd/archures.c | 5 + ++ bfd/bfd-in2.h | 48 + ++ bfd/config.bfd | 15 + ++ bfd/configure | 2 + ++ bfd/configure.ac | 2 + ++ bfd/cpu-loongarch.c | 38 + ++ bfd/elf-bfd.h | 9 + ++ bfd/elf.c | 109 + ++ bfd/elfnn-loongarch.c | 3287 ++++++++++++++++++++++++++ ++ bfd/elfxx-loongarch.c | 172 ++ ++ bfd/elfxx-loongarch.h | 11 + ++ bfd/libbfd.h | 43 + ++ bfd/reloc.c | 89 + ++ bfd/targets.c | 7 + ++ config.guess | 3 + ++ config.sub | 1 + ++ gdb/arch/loongarch-insn.h | 352 +++ ++ gdb/arch/loongarch-linux-nat.c | 94 + ++ gdb/arch/loongarch-linux-nat.h | 35 + ++ gdb/arch/loongarch.c | 66 + ++ gdb/arch/loongarch.h | 24 + ++ gdb/configure.host | 3 + ++ gdb/configure.nat | 4 + ++ gdb/configure.tgt | 8 + ++ gdb/doc/gdb.texinfo | 10 + ++ gdb/features/Makefile | 10 + ++ gdb/features/loongarch/base32.c | 47 + ++ gdb/features/loongarch/base32.xml | 45 + ++ gdb/features/loongarch/base64.c | 47 + ++ gdb/features/loongarch/base64.xml | 45 + ++ gdb/features/loongarch/fpu32.c | 54 + ++ gdb/features/loongarch/fpu32.xml | 53 + ++ gdb/features/loongarch/fpu64.c | 62 + ++ gdb/features/loongarch/fpu64.xml | 58 + ++ gdb/features/loongarch/lasx.c | 80 + ++ gdb/features/loongarch/lasx.xml | 59 + ++ gdb/features/loongarch/lbt32.c | 19 + ++ gdb/features/loongarch/lbt32.xml | 17 + ++ gdb/features/loongarch/lbt64.c | 19 + ++ gdb/features/loongarch/lbt64.xml | 17 + ++ gdb/features/loongarch/lsx.c | 80 + ++ gdb/features/loongarch/lsx.xml | 59 + ++ gdb/loongarch-linux-nat.c | 852 +++++++ ++ gdb/loongarch-linux-tdep.c | 564 +++++ ++ gdb/loongarch-linux-tdep.h | 28 + ++ gdb/loongarch-tdep.c | 2613 ++++++++++++++++++++ ++ gdb/loongarch-tdep.h | 99 + ++ gdb/nat/loongarch-linux-watch.c | 330 +++ ++ gdb/nat/loongarch-linux-watch.h | 132 ++ ++ gdb/remote.c | 25 + ++ gdb/target.h | 3 + ++ gdb/testsuite/gdb.base/dump.exp | 4 + ++ gdb/testsuite/gdb.base/float.exp | 2 + ++ gdb/testsuite/gdb.xml/tdesc-regs.exp | 5 + ++ include/dis-asm.h | 1 + ++ include/elf/common.h | 9 + ++ include/elf/loongarch.h | 95 + ++ include/opcode/loongarch.h | 215 ++ ++ opcodes/Makefile.am | 3 + ++ opcodes/Makefile.in | 6 + ++ opcodes/configure | 1 + ++ opcodes/configure.ac | 1 + ++ opcodes/disassemble.c | 9 + ++ opcodes/disassemble.h | 1 + ++ opcodes/loongarch-coder.c | 446 ++++ ++ opcodes/loongarch-dis.c | 311 +++ ++ opcodes/loongarch-opc.c | 2152 +++++++++++++++++ ++ 69 files changed, 13155 insertions(+) ++ create mode 100644 bfd/cpu-loongarch.c ++ create mode 100644 bfd/elfnn-loongarch.c ++ create mode 100644 bfd/elfxx-loongarch.c ++ create mode 100644 bfd/elfxx-loongarch.h ++ create mode 100644 gdb/arch/loongarch-insn.h ++ create mode 100644 gdb/arch/loongarch-linux-nat.c ++ create mode 100644 gdb/arch/loongarch-linux-nat.h ++ create mode 100644 gdb/arch/loongarch.c ++ create mode 100644 gdb/arch/loongarch.h ++ create mode 100644 gdb/features/loongarch/base32.c ++ create mode 100644 gdb/features/loongarch/base32.xml ++ create mode 100644 gdb/features/loongarch/base64.c ++ create mode 100644 gdb/features/loongarch/base64.xml ++ create mode 100644 gdb/features/loongarch/fpu32.c ++ create mode 100644 gdb/features/loongarch/fpu32.xml ++ create mode 100644 gdb/features/loongarch/fpu64.c ++ create mode 100644 gdb/features/loongarch/fpu64.xml ++ create mode 100644 gdb/features/loongarch/lasx.c ++ create mode 100644 gdb/features/loongarch/lasx.xml ++ create mode 100644 gdb/features/loongarch/lbt32.c ++ create mode 100644 gdb/features/loongarch/lbt32.xml ++ create mode 100644 gdb/features/loongarch/lbt64.c ++ create mode 100644 gdb/features/loongarch/lbt64.xml ++ create mode 100644 gdb/features/loongarch/lsx.c ++ create mode 100644 gdb/features/loongarch/lsx.xml ++ create mode 100644 gdb/loongarch-linux-nat.c ++ create mode 100644 gdb/loongarch-linux-tdep.c ++ create mode 100644 gdb/loongarch-linux-tdep.h ++ create mode 100644 gdb/loongarch-tdep.c ++ create mode 100644 gdb/loongarch-tdep.h ++ create mode 100644 gdb/nat/loongarch-linux-watch.c ++ create mode 100644 gdb/nat/loongarch-linux-watch.h ++ create mode 100644 include/elf/loongarch.h ++ create mode 100644 include/opcode/loongarch.h ++ create mode 100644 opcodes/loongarch-coder.c ++ create mode 100644 opcodes/loongarch-dis.c ++ create mode 100644 opcodes/loongarch-opc.c ++ ++diff --git gdb-10.2/bfd/Makefile.am gdb-10.2/bfd/Makefile.am ++index d07c960..df68246 100644 ++--- gdb-10.2/bfd/Makefile.am +++++ gdb-10.2/bfd/Makefile.am ++@@ -118,6 +118,7 @@ ALL_MACHINES = \ ++ cpu-ip2k.lo \ ++ cpu-iq2000.lo \ ++ cpu-lm32.lo \ +++ cpu-loongarch.lo \ ++ cpu-m10200.lo \ ++ cpu-m10300.lo \ ++ cpu-m32c.lo \ ++@@ -202,6 +203,7 @@ ALL_MACHINES_CFILES = \ ++ cpu-ip2k.c \ ++ cpu-iq2000.c \ ++ cpu-lm32.c \ +++ cpu-loongarch.c \ ++ cpu-m10200.c \ ++ cpu-m10300.c \ ++ cpu-m32c.c \ ++@@ -548,6 +550,8 @@ BFD64_BACKENDS = \ ++ elf64-ia64.lo \ ++ elf64-ia64-vms.lo \ ++ elfxx-ia64.lo \ +++ elf32-loongarch.lo \ +++ elf64-loongarch.lo \ ++ elfn32-mips.lo \ ++ elf64-mips.lo \ ++ elfxx-mips.lo \ ++@@ -665,6 +669,7 @@ SOURCE_CFILES = \ ++ BUILD_CFILES = \ ++ elf32-aarch64.c elf64-aarch64.c \ ++ elf32-ia64.c elf64-ia64.c \ +++ elf32-loongarch.c elf64-loongarch.c \ ++ elf32-riscv.c elf64-riscv.c \ ++ peigen.c pepigen.c pex64igen.c ++ ++@@ -842,6 +847,18 @@ elf64-ia64.c : elfnn-ia64.c ++ echo "#line 1 \"elfnn-ia64.c\"" > $@ ++ $(SED) -e s/NN/64/g < $< >> $@ ++ +++elf32-loongarch.c : elfnn-loongarch.c +++ rm -f elf32-loongarch.c +++ echo "#line 1 \"$(srcdir)/elfnn-loongarch.c\"" > elf32-loongarch.new +++ sed -e s/NN/32/g < $(srcdir)/elfnn-loongarch.c >> elf32-loongarch.new +++ mv -f elf32-loongarch.new elf32-loongarch.c +++ +++elf64-loongarch.c : elfnn-loongarch.c +++ rm -f elf64-loongarch.c +++ echo "#line 1 \"$(srcdir)/elfnn-loongarch.c\"" > elf64-loongarch.new +++ sed -e s/NN/64/g < $(srcdir)/elfnn-loongarch.c >> elf64-loongarch.new +++ mv -f elf64-loongarch.new elf64-loongarch.c +++ ++ elf32-riscv.c : elfnn-riscv.c ++ echo "#line 1 \"elfnn-riscv.c\"" > $@ ++ $(SED) -e s/NN/32/g < $< >> $@ ++diff --git gdb-10.2/bfd/Makefile.in gdb-10.2/bfd/Makefile.in ++index 9cad4da..f48b1fc 100644 ++--- gdb-10.2/bfd/Makefile.in +++++ gdb-10.2/bfd/Makefile.in ++@@ -543,6 +543,7 @@ ALL_MACHINES = \ ++ cpu-ip2k.lo \ ++ cpu-iq2000.lo \ ++ cpu-lm32.lo \ +++ cpu-loongarch.lo \ ++ cpu-m10200.lo \ ++ cpu-m10300.lo \ ++ cpu-m32c.lo \ ++@@ -627,6 +628,7 @@ ALL_MACHINES_CFILES = \ ++ cpu-ip2k.c \ ++ cpu-iq2000.c \ ++ cpu-lm32.c \ +++ cpu-loongarch.c \ ++ cpu-m10200.c \ ++ cpu-m10300.c \ ++ cpu-m32c.c \ ++@@ -966,6 +968,9 @@ BFD64_BACKENDS = \ ++ coff-x86_64.lo \ ++ coff64-rs6000.lo \ ++ elf32-ia64.lo \ +++ elf32-loongarch.lo \ +++ elf64-loongarch.lo \ +++ elfxx-loongarch.lo \ ++ elf32-mips.lo \ ++ elf32-score.lo \ ++ elf32-score7.lo \ ++@@ -1028,6 +1033,7 @@ BFD64_BACKENDS_CFILES = \ ++ elfn32-mips.c \ ++ elfxx-aarch64.c \ ++ elfxx-ia64.c \ +++ elfxx-loongarch.c \ ++ elfxx-mips.c \ ++ elfxx-riscv.c \ ++ mach-o-aarch64.c \ ++@@ -1091,6 +1097,7 @@ SOURCE_CFILES = \ ++ BUILD_CFILES = \ ++ elf32-aarch64.c elf64-aarch64.c \ ++ elf32-ia64.c elf64-ia64.c \ +++ elf32-loongarch.c elf64-loongarch.c \ ++ elf32-riscv.c elf64-riscv.c \ ++ peigen.c pepigen.c pex64igen.c ++ ++@@ -1349,6 +1356,7 @@ distclean-compile: ++ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-k1om.Plo@am__quote@ ++ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-l1om.Plo@am__quote@ ++ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-lm32.Plo@am__quote@ +++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-loongarch.Plo@am__quote@ ++ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-m10200.Plo@am__quote@ ++ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-m10300.Plo@am__quote@ ++ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-m32c.Plo@am__quote@ ++@@ -1442,6 +1450,7 @@ distclean-compile: ++ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-ip2k.Plo@am__quote@ ++ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-iq2000.Plo@am__quote@ ++ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-lm32.Plo@am__quote@ +++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-loongarch.Plo@am__quote@ ++ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-m32c.Plo@am__quote@ ++ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-m32r.Plo@am__quote@ ++ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-m68hc11.Plo@am__quote@ ++@@ -1492,6 +1501,7 @@ distclean-compile: ++ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf64-hppa.Plo@am__quote@ ++ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf64-ia64-vms.Plo@am__quote@ ++ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf64-ia64.Plo@am__quote@ +++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf64-loongarch.Plo@am__quote@ ++ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf64-mips.Plo@am__quote@ ++ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf64-mmix.Plo@am__quote@ ++ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf64-nfp.Plo@am__quote@ ++@@ -1506,6 +1516,7 @@ distclean-compile: ++ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elfn32-mips.Plo@am__quote@ ++ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elfxx-aarch64.Plo@am__quote@ ++ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elfxx-ia64.Plo@am__quote@ +++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elfxx-loongarch.Plo@am__quote@ ++ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elfxx-mips.Plo@am__quote@ ++ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elfxx-riscv.Plo@am__quote@ ++ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elfxx-sparc.Plo@am__quote@ ++@@ -1976,6 +1987,18 @@ elf32-riscv.c : elfnn-riscv.c ++ echo "#line 1 \"elfnn-riscv.c\"" > $@ ++ $(SED) -e s/NN/32/g < $< >> $@ ++ +++elf32-loongarch.c : elfnn-loongarch.c +++ rm -f elf32-loongarch.c +++ echo "#line 1 \"$(srcdir)/elfnn-loongarch.c\"" > elf32-loongarch.new +++ sed -e s/NN/32/g < $(srcdir)/elfnn-loongarch.c >> elf32-loongarch.new +++ mv -f elf32-loongarch.new elf32-loongarch.c +++ +++elf64-loongarch.c : elfnn-loongarch.c +++ rm -f elf64-loongarch.c +++ echo "#line 1 \"$(srcdir)/elfnn-loongarch.c\"" > elf64-loongarch.new +++ sed -e s/NN/64/g < $(srcdir)/elfnn-loongarch.c >> elf64-loongarch.new +++ mv -f elf64-loongarch.new elf64-loongarch.c +++ ++ elf64-riscv.c : elfnn-riscv.c ++ echo "#line 1 \"elfnn-riscv.c\"" > $@ ++ $(SED) -e s/NN/64/g < $< >> $@ ++diff --git gdb-10.2/bfd/archures.c gdb-10.2/bfd/archures.c ++index 5069864..7a5d7f8 100644 ++--- gdb-10.2/bfd/archures.c +++++ gdb-10.2/bfd/archures.c ++@@ -545,6 +545,9 @@ DESCRIPTION ++ . bfd_arch_nfp, {* Netronome Flow Processor *} ++ .#define bfd_mach_nfp3200 0x3200 ++ .#define bfd_mach_nfp6000 0x6000 +++. bfd_arch_loongarch, {* Loongarch *} +++.#define bfd_mach_loongarch32 1 +++.#define bfd_mach_loongarch64 2 ++ . bfd_arch_csky, {* C-SKY. *} ++ .#define bfd_mach_ck_unknown 0 ++ .#define bfd_mach_ck510 1 ++@@ -636,6 +639,7 @@ extern const bfd_arch_info_type bfd_iq2000_arch; ++ extern const bfd_arch_info_type bfd_k1om_arch; ++ extern const bfd_arch_info_type bfd_l1om_arch; ++ extern const bfd_arch_info_type bfd_lm32_arch; +++extern const bfd_arch_info_type bfd_loongarch_arch; ++ extern const bfd_arch_info_type bfd_m32c_arch; ++ extern const bfd_arch_info_type bfd_m32r_arch; ++ extern const bfd_arch_info_type bfd_m68hc11_arch; ++@@ -725,6 +729,7 @@ static const bfd_arch_info_type * const bfd_archures_list[] = ++ &bfd_k1om_arch, ++ &bfd_l1om_arch, ++ &bfd_lm32_arch, +++ &bfd_loongarch_arch, ++ &bfd_m32c_arch, ++ &bfd_m32r_arch, ++ &bfd_m68hc11_arch, ++diff --git gdb-10.2/bfd/bfd-in2.h gdb-10.2/bfd/bfd-in2.h ++index 935ba53..b911b7e 100644 ++--- gdb-10.2/bfd/bfd-in2.h +++++ gdb-10.2/bfd/bfd-in2.h ++@@ -1945,6 +1945,9 @@ enum bfd_architecture ++ bfd_arch_nfp, /* Netronome Flow Processor */ ++ #define bfd_mach_nfp3200 0x3200 ++ #define bfd_mach_nfp6000 0x6000 +++ bfd_arch_loongarch, /* LoongARCH */ +++#define bfd_mach_loongarch32 1 +++#define bfd_mach_loongarch64 2 ++ bfd_arch_csky, /* C-SKY. */ ++ #define bfd_mach_ck_unknown 0 ++ #define bfd_mach_ck510 1 ++@@ -6204,6 +6207,51 @@ assembler and not (currently) written to any object files. */ ++ BFD_RELOC_WASM32_INDEX, ++ BFD_RELOC_WASM32_PLT_SIG, ++ +++/* LoongISA relocations. */ +++ BFD_RELOC_LARCH_TLS_DTPMOD32, +++ BFD_RELOC_LARCH_TLS_DTPREL32, +++ BFD_RELOC_LARCH_TLS_DTPMOD64, +++ BFD_RELOC_LARCH_TLS_DTPREL64, +++ BFD_RELOC_LARCH_TLS_TPREL32, +++ BFD_RELOC_LARCH_TLS_TPREL64, +++ BFD_RELOC_LARCH_MARK_LA, +++ BFD_RELOC_LARCH_MARK_PCREL, +++ BFD_RELOC_LARCH_SOP_PUSH_PCREL, +++ BFD_RELOC_LARCH_SOP_PUSH_ABSOLUTE, +++ BFD_RELOC_LARCH_SOP_PUSH_DUP, +++ BFD_RELOC_LARCH_SOP_PUSH_GPREL, +++ BFD_RELOC_LARCH_SOP_PUSH_TLS_TPREL, +++ BFD_RELOC_LARCH_SOP_PUSH_TLS_GOT, +++ BFD_RELOC_LARCH_SOP_PUSH_TLS_GD, +++ BFD_RELOC_LARCH_SOP_PUSH_PLT_PCREL, +++ BFD_RELOC_LARCH_SOP_ASSERT, +++ BFD_RELOC_LARCH_SOP_NOT, +++ BFD_RELOC_LARCH_SOP_SUB, +++ BFD_RELOC_LARCH_SOP_SL, +++ BFD_RELOC_LARCH_SOP_SR, +++ BFD_RELOC_LARCH_SOP_ADD, +++ BFD_RELOC_LARCH_SOP_AND, +++ BFD_RELOC_LARCH_SOP_IF_ELSE, +++ BFD_RELOC_LARCH_SOP_POP_32_S_10_5, +++ BFD_RELOC_LARCH_SOP_POP_32_U_10_12, +++ BFD_RELOC_LARCH_SOP_POP_32_S_10_12, +++ BFD_RELOC_LARCH_SOP_POP_32_S_10_16, +++ BFD_RELOC_LARCH_SOP_POP_32_S_10_16_S2, +++ BFD_RELOC_LARCH_SOP_POP_32_S_5_20, +++ BFD_RELOC_LARCH_SOP_POP_32_S_0_5_10_16_S2, +++ BFD_RELOC_LARCH_SOP_POP_32_S_0_10_10_16_S2, +++ BFD_RELOC_LARCH_SOP_POP_32_U, +++ BFD_RELOC_LARCH_ADD8, +++ BFD_RELOC_LARCH_ADD16, +++ BFD_RELOC_LARCH_ADD24, +++ BFD_RELOC_LARCH_ADD32, +++ BFD_RELOC_LARCH_ADD64, +++ BFD_RELOC_LARCH_SUB8, +++ BFD_RELOC_LARCH_SUB16, +++ BFD_RELOC_LARCH_SUB24, +++ BFD_RELOC_LARCH_SUB32, +++ BFD_RELOC_LARCH_SUB64, +++ ++ /* C-SKY relocations. */ ++ BFD_RELOC_CKCORE_NONE, ++ BFD_RELOC_CKCORE_ADDR32, ++diff --git gdb-10.2/bfd/config.bfd gdb-10.2/bfd/config.bfd ++index 6c2919e..75f2d7c 100644 ++--- gdb-10.2/bfd/config.bfd +++++ gdb-10.2/bfd/config.bfd ++@@ -183,6 +183,7 @@ hppa*) targ_archs=bfd_hppa_arch ;; ++ i[3-7]86) targ_archs=bfd_i386_arch ;; ++ ia16) targ_archs=bfd_i386_arch ;; ++ lm32) targ_archs=bfd_lm32_arch ;; +++loongarch*) targ_archs=bfd_loongarch_arch ;; ++ m6811*|m68hc11*) targ_archs="bfd_m68hc11_arch bfd_m68hc12_arch bfd_m9s12x_arch bfd_m9s12xg_arch" ;; ++ m6812*|m68hc12*) targ_archs="bfd_m68hc12_arch bfd_m68hc11_arch bfd_m9s12x_arch bfd_m9s12xg_arch" ;; ++ m68*) targ_archs=bfd_m68k_arch ;; ++@@ -768,6 +769,20 @@ case "${targ}" in ++ targ_selvecs=lm32_elf32_vec ++ ;; ++ +++#ifdef BFD64 +++ loongarch32-*) +++ targ_defvec=loongarch_elf32_vec +++ targ_selvecs="loongarch_elf32_vec" +++ want64=false +++ ;; +++ +++ loongarch64-*) +++ targ_defvec=loongarch_elf64_vec +++ targ_selvecs="loongarch_elf32_vec loongarch_elf64_vec" +++ want64=true +++ ;; +++#endif +++ ++ m32c-*-elf | m32c-*-rtems*) ++ targ_defvec=m32c_elf32_vec ++ targ_underscore=yes ++diff --git gdb-10.2/bfd/configure gdb-10.2/bfd/configure ++index a9c4fd9..251439e 100755 ++--- gdb-10.2/bfd/configure +++++ gdb-10.2/bfd/configure ++@@ -14836,6 +14836,8 @@ do ++ l1om_elf64_fbsd_vec) tb="$tb elf64-x86-64.lo elfxx-x86.lo elf-ifunc.lo elf64.lo $elf"; target_size=64 ;; ++ lm32_elf32_vec) tb="$tb elf32-lm32.lo elf32.lo $elf" ;; ++ lm32_elf32_fdpic_vec) tb="$tb elf32-lm32.lo elf32.lo $elf" ;; +++ loongarch_elf32_vec) tb="$tb elf32-loongarch.lo elfxx-loongarch.lo elf32.lo elf-ifunc.lo $elf" ;; +++ loongarch_elf64_vec) tb="$tb elf64-loongarch.lo elf64.lo elfxx-loongarch.lo elf32.lo elf-ifunc.lo $elf"; target_size=64 ;; ++ m32c_elf32_vec) tb="$tb elf32-m32c.lo elf32.lo $elf" ;; ++ m32r_elf32_vec) tb="$tb elf32-m32r.lo elf32.lo $elf" ;; ++ m32r_elf32_le_vec) tb="$tb elf32-m32r.lo elf32.lo $elf" ;; ++diff --git gdb-10.2/bfd/configure.ac gdb-10.2/bfd/configure.ac ++index f62659a..e97c9fc 100644 ++--- gdb-10.2/bfd/configure.ac +++++ gdb-10.2/bfd/configure.ac ++@@ -542,6 +542,8 @@ do ++ l1om_elf64_fbsd_vec) tb="$tb elf64-x86-64.lo elfxx-x86.lo elf-ifunc.lo elf64.lo $elf"; target_size=64 ;; ++ lm32_elf32_vec) tb="$tb elf32-lm32.lo elf32.lo $elf" ;; ++ lm32_elf32_fdpic_vec) tb="$tb elf32-lm32.lo elf32.lo $elf" ;; +++ loongarch_elf32_vec) tb="$tb elf32-loongarch.lo elfxx-loongarch.lo elf32.lo elf-ifunc.lo $elf" ;; +++ loongarch_elf64_vec) tb="$tb elf64-loongarch.lo elf64.lo elfxx-loongarch.lo elf32.lo elf-ifunc.lo $elf"; target_size=64 ;; ++ m32c_elf32_vec) tb="$tb elf32-m32c.lo elf32.lo $elf" ;; ++ m32r_elf32_vec) tb="$tb elf32-m32r.lo elf32.lo $elf" ;; ++ m32r_elf32_le_vec) tb="$tb elf32-m32r.lo elf32.lo $elf" ;; ++diff --git gdb-10.2/bfd/cpu-loongarch.c gdb-10.2/bfd/cpu-loongarch.c ++new file mode 100644 ++index 0000000..c5579f2 ++--- /dev/null +++++ gdb-10.2/bfd/cpu-loongarch.c ++@@ -0,0 +1,38 @@ +++#include "sysdep.h" +++#include "bfd.h" +++#include "libbfd.h" +++ +++static const bfd_arch_info_type bfd_loongarch32_arch = +++{ +++ 32, /* 32 bits in a word. */ +++ 32, /* 64 bits in an address. */ +++ 8, /* 8 bits in a byte. */ +++ bfd_arch_loongarch, /* Architecture. */ +++ bfd_mach_loongarch32, /* Machine number - 0 for now. */ +++ "loongarch32", /* Architecture name. */ +++ "Loongarch32", /* Printable name. */ +++ 3, /* Section align power. */ +++ FALSE, /* This is the default architecture. */ +++ bfd_default_compatible, /* Architecture comparison function. */ +++ bfd_default_scan, /* String to architecture conversion. */ +++ bfd_arch_default_fill, /* Default fill. */ +++ NULL, /* Next in list. */ +++}; +++ +++const bfd_arch_info_type bfd_loongarch_arch = +++{ +++ 32, /* 32 bits in a word. */ +++ 64, /* 64 bits in an address. */ +++ 8, /* 8 bits in a byte. */ +++ bfd_arch_loongarch, /* Architecture. */ +++ bfd_mach_loongarch64, /* Machine number of loongarch64 is larger so that loongarch64 is compatible to loongarch32 */ +++ "loongarch64", /* Architecture name. */ +++ "Loongarch64", /* Printable name. */ +++ 3, /* Section align power. */ +++ TRUE, /* This is the default architecture. */ +++ bfd_default_compatible, /* Architecture comparison function. */ +++ bfd_default_scan, /* String to architecture conversion. */ +++ bfd_arch_default_fill, /* Default fill. */ +++ &bfd_loongarch32_arch, /* Next in list. */ +++}; +++ ++diff --git gdb-10.2/bfd/elf-bfd.h gdb-10.2/bfd/elf-bfd.h ++index eebdf9a..321c5e5 100644 ++--- gdb-10.2/bfd/elf-bfd.h +++++ gdb-10.2/bfd/elf-bfd.h ++@@ -500,6 +500,7 @@ enum elf_target_id ++ I386_ELF_DATA, ++ IA64_ELF_DATA, ++ LM32_ELF_DATA, +++ LARCH_ELF_DATA, ++ M32R_ELF_DATA, ++ M68HC11_ELF_DATA, ++ M68K_ELF_DATA, ++@@ -2795,6 +2796,14 @@ extern char *elfcore_write_aarch_pauth ++ (bfd *, char *, int *, const void *, int); ++ extern char *elfcore_write_arc_v2 ++ (bfd *, char *, int *, const void *, int); +++extern char *elfcore_write_loongarch_cpucfg +++ (bfd *, char *, int *, const void *, int); +++extern char *elfcore_write_loongarch_lbt +++ (bfd *, char *, int *, const void *, int); +++extern char *elfcore_write_loongarch_lsx +++ (bfd *, char *, int *, const void *, int); +++extern char *elfcore_write_loongarch_lasx +++ (bfd *, char *, int *, const void *, int); ++ extern char *elfcore_write_lwpstatus ++ (bfd *, char *, int *, long, int, const void *); ++ extern char *elfcore_write_register_note ++diff --git gdb-10.2/bfd/elf.c gdb-10.2/bfd/elf.c ++index 5a02f8d..d60c346 100644 ++--- gdb-10.2/bfd/elf.c +++++ gdb-10.2/bfd/elf.c ++@@ -9903,6 +9903,30 @@ elfcore_grok_arc_v2 (bfd *abfd, Elf_Internal_Note *note) ++ return elfcore_make_note_pseudosection (abfd, ".reg-arc-v2", note); ++ } ++ +++static bfd_boolean +++elfcore_grok_loongarch_cpucfg (bfd *abfd, Elf_Internal_Note *note) +++{ +++ return elfcore_make_note_pseudosection (abfd, ".reg-loongarch-cpucfg", note); +++} +++ +++static bfd_boolean +++elfcore_grok_loongarch_lbt (bfd *abfd, Elf_Internal_Note *note) +++{ +++ return elfcore_make_note_pseudosection (abfd, ".reg-loongarch-lbt", note); +++} +++ +++static bfd_boolean +++elfcore_grok_loongarch_lsx (bfd *abfd, Elf_Internal_Note *note) +++{ +++ return elfcore_make_note_pseudosection (abfd, ".reg-loongarch-lsx", note); +++} +++ +++static bfd_boolean +++elfcore_grok_loongarch_lasx (bfd *abfd, Elf_Internal_Note *note) +++{ +++ return elfcore_make_note_pseudosection (abfd, ".reg-loongarch-lasx", note); +++} +++ ++ #if defined (HAVE_PRPSINFO_T) ++ typedef prpsinfo_t elfcore_psinfo_t; ++ #if defined (HAVE_PRPSINFO32_T) /* Sparc64 cross Sparc32 */ ++@@ -10560,6 +10584,34 @@ elfcore_grok_note (bfd *abfd, Elf_Internal_Note *note) ++ else ++ return TRUE; ++ +++ case NT_LARCH_CPUCFG: +++ if (note->namesz == 6 +++ && strcmp (note->namedata, "LINUX") == 0) +++ return elfcore_grok_loongarch_cpucfg (abfd, note); +++ else +++ return TRUE; +++ +++ case NT_LARCH_LBT: +++ if (note->namesz == 6 +++ && strcmp (note->namedata, "LINUX") == 0) +++ return elfcore_grok_loongarch_lbt (abfd, note); +++ else +++ return TRUE; +++ +++ case NT_LARCH_LSX: +++ if (note->namesz == 6 +++ && strcmp (note->namedata, "LINUX") == 0) +++ return elfcore_grok_loongarch_lsx (abfd, note); +++ else +++ return TRUE; +++ +++ case NT_LARCH_LASX: +++ if (note->namesz == 6 +++ && strcmp (note->namedata, "LINUX") == 0) +++ return elfcore_grok_loongarch_lasx (abfd, note); +++ else +++ return TRUE; +++ ++ case NT_PRPSINFO: ++ case NT_PSINFO: ++ if (bed->elf_backend_grok_psinfo) ++@@ -11941,6 +11993,55 @@ elfcore_write_arc_v2 (bfd *abfd, ++ note_name, NT_ARC_V2, arc_v2, size); ++ } ++ +++char * +++elfcore_write_loongarch_cpucfg (bfd *abfd, +++ char *buf, +++ int *bufsiz, +++ const void *loongarch_cpucfg, +++ int size) +++{ +++ char *note_name = "LINUX"; +++ return elfcore_write_note (abfd, buf, bufsiz, +++ note_name, NT_LARCH_CPUCFG, +++ loongarch_cpucfg, size); +++} +++ +++char * +++elfcore_write_loongarch_lbt (bfd *abfd, +++ char *buf, +++ int *bufsiz, +++ const void *loongarch_lbt, +++ int size) +++{ +++ char *note_name = "LINUX"; +++ return elfcore_write_note (abfd, buf, bufsiz, +++ note_name, NT_LARCH_LBT, loongarch_lbt, size); +++} +++ +++char * +++elfcore_write_loongarch_lsx (bfd *abfd, +++ char *buf, +++ int *bufsiz, +++ const void *loongarch_lsx, +++ int size) +++{ +++ char *note_name = "LINUX"; +++ return elfcore_write_note (abfd, buf, bufsiz, +++ note_name, NT_LARCH_LSX, loongarch_lsx, size); +++} +++ +++char * +++elfcore_write_loongarch_lasx (bfd *abfd, +++ char *buf, +++ int *bufsiz, +++ const void *loongarch_lasx, +++ int size) +++{ +++ char *note_name = "LINUX"; +++ return elfcore_write_note (abfd, buf, bufsiz, +++ note_name, NT_LARCH_LASX, loongarch_lasx, size); +++} +++ ++ char * ++ elfcore_write_register_note (bfd *abfd, ++ char *buf, ++@@ -12019,6 +12120,14 @@ elfcore_write_register_note (bfd *abfd, ++ return elfcore_write_aarch_hw_break (abfd, buf, bufsiz, data, size); ++ if (strcmp (section, ".reg-aarch-hw-watch") == 0) ++ return elfcore_write_aarch_hw_watch (abfd, buf, bufsiz, data, size); +++ if (strcmp (section, ".reg-loongarch-cpucfg") == 0) +++ return elfcore_write_loongarch_cpucfg (abfd, buf, bufsiz, data, size); +++ if (strcmp (section, ".reg-loongarch-lbt") == 0) +++ return elfcore_write_loongarch_lbt (abfd, buf, bufsiz, data, size); +++ if (strcmp (section, ".reg-loongarch-lsx") == 0) +++ return elfcore_write_loongarch_lsx (abfd, buf, bufsiz, data, size); +++ if (strcmp (section, ".reg-loongarch-lasx") == 0) +++ return elfcore_write_loongarch_lasx (abfd, buf, bufsiz, data, size); ++ if (strcmp (section, ".reg-aarch-sve") == 0) ++ return elfcore_write_aarch_sve (abfd, buf, bufsiz, data, size); ++ if (strcmp (section, ".reg-aarch-pauth") == 0) ++diff --git gdb-10.2/bfd/elfnn-loongarch.c gdb-10.2/bfd/elfnn-loongarch.c ++new file mode 100644 ++index 0000000..296e94a ++--- /dev/null +++++ gdb-10.2/bfd/elfnn-loongarch.c ++@@ -0,0 +1,3287 @@ +++#include "sysdep.h" +++#include "bfd.h" +++#include "libbfd.h" +++#define ARCH_SIZE NN +++#include "elf-bfd.h" +++#include "objalloc.h" +++#include "elf/loongarch.h" +++#include "elfxx-loongarch.h" +++ +++static bfd_boolean +++loongarch_info_to_howto_rela (bfd *abfd ATTRIBUTE_UNUSED, +++ arelent *cache_ptr, +++ Elf_Internal_Rela *dst) +++{ +++ cache_ptr->howto = loongarch_elf_rtype_to_howto (ELFNN_R_TYPE (dst->r_info)); +++ return cache_ptr->howto != NULL; +++} +++ +++/* Loongarch ELF linker hash entry. */ +++ +++struct loongarch_elf_link_hash_entry +++{ +++ struct elf_link_hash_entry elf; +++ +++ /* Track dynamic relocs copied for this symbol. */ +++ struct elf_dyn_relocs *dyn_relocs; +++ +++#define GOT_UNKNOWN 0 +++#define GOT_NORMAL 1 +++#define GOT_TLS_GD 2 +++#define GOT_TLS_IE 4 +++#define GOT_TLS_LE 8 +++ char tls_type; +++}; +++ +++#define loongarch_elf_hash_entry(ent) \ +++ ((struct loongarch_elf_link_hash_entry *)(ent)) +++ +++struct _bfd_loongarch_elf_obj_tdata +++{ +++ struct elf_obj_tdata root; +++ +++ /* tls_type for each local got entry. */ +++ char *local_got_tls_type; +++}; +++ +++#define _bfd_loongarch_elf_tdata(abfd) \ +++ ((struct _bfd_loongarch_elf_obj_tdata *) (abfd)->tdata.any) +++ +++#define _bfd_loongarch_elf_local_got_tls_type(abfd) \ +++ (_bfd_loongarch_elf_tdata (abfd)->local_got_tls_type) +++ +++#define _bfd_loongarch_elf_tls_type(abfd, h, symndx) \ +++ (*((h) != NULL ? &loongarch_elf_hash_entry (h)->tls_type \ +++ : &_bfd_loongarch_elf_local_got_tls_type (abfd) [symndx])) +++ +++#define is_loongarch_elf(bfd) \ +++ (bfd_get_flavour (bfd) == bfd_target_elf_flavour \ +++ && elf_tdata (bfd) != NULL \ +++ && elf_object_id (bfd) == LARCH_ELF_DATA) +++ +++struct loongarch_elf_link_hash_table +++{ +++ struct elf_link_hash_table elf; +++ +++ /* Short-cuts to get to dynamic linker sections. */ +++ asection *sdyntdata; +++ +++ /* Small local sym to section mapping cache. */ +++ struct sym_cache sym_cache; +++ +++ /* Used by local STT_GNU_IFUNC symbols. */ +++ htab_t loc_hash_table; +++ void *loc_hash_memory; +++ +++ /* The max alignment of output sections. */ +++ bfd_vma max_alignment; +++}; +++ +++/* Get the Loongarch ELF linker hash table from a link_info structure. */ +++#define loongarch_elf_hash_table(p) \ +++ (elf_hash_table_id ((struct elf_link_hash_table *) ((p)->hash)) \ +++ == LARCH_ELF_DATA \ +++ ? ((struct loongarch_elf_link_hash_table *) ((p)->hash)) : NULL) +++ +++#define MINUS_ONE ((bfd_vma)0 - 1) +++ +++#define sec_addr(sec) ((sec)->output_section->vma + (sec)->output_offset) +++ +++#define LARCH_ELF_LOG_WORD_BYTES (ARCH_SIZE == 32 ? 2 : 3) +++#define LARCH_ELF_WORD_BYTES (1 << LARCH_ELF_LOG_WORD_BYTES) +++ +++#define PLT_HEADER_INSNS 8 +++#define PLT_HEADER_SIZE (PLT_HEADER_INSNS * 4) +++ +++#define PLT_ENTRY_INSNS 4 +++#define PLT_ENTRY_SIZE (PLT_ENTRY_INSNS * 4) +++ +++#define GOT_ENTRY_SIZE (LARCH_ELF_WORD_BYTES) +++ +++/* .got.plt的前两项预留。我们约定: +++ 第一项在运行时被动态连接器填入_dl_runtime_resolve的地址 +++ 第二项在连接时,非0指plt header的地址(在no-pic下或prelink)。 +++ 第二项在运行时被动态连接器填入本模块的struct link_map实例的地址。 +++ 详见$glibc/sysdeps/loongarch/dl-machine.h中的elf_machine_runtime_setup */ +++#define GOTPLT_HEADER_SIZE (GOT_ENTRY_SIZE * 2) +++ +++/* .got和.got.plt不合并的好处是,.got.plt和.plt的entry是顺序对应的。 +++ 设法使得stub的size为2的幂,知道.plt和stub的地址就知道了index。 */ +++#define elf_backend_want_got_plt 1 +++ +++#define elf_backend_plt_readonly 1 +++ +++#define elf_backend_want_plt_sym 0 +++/* 1. 本来想着定义_PROCEDURE_LINKAGE_TABLE_,多了不嫌多。 +++ 2. 但实际上,这个符号会使得GDB调试ifunc函数失效。因为lazy-bind的情况下, +++ plt GOT entry中的地址都指向这个符号;GDB读取plt GOT entry来确定ifunc的 +++ 目标函数,从而以为_PROCEDURE_LINKAGE_TABLE_就是ifunc的目标函数(好奇的人 +++ 可以把断点打在elf_gnu_ifunc_record_cache上面看一下GDB的行为,总之是校验从 +++ GOT entry中拿到的地址,结果发现 'BMSYMBOL_VALUE_ADDRESS (msym) == addr' +++ 为真),然后直接跳转到plt header上面了,这当然不行。 +++ 3. 我们期望,调用ifunc函数时,要么跳到对应的plt stub上;要么GDB运行一遍 +++ resolver得到ifunc目标函数的地址后再调用(这是GDB公共代码的做法)。 +++ 4. 观察了aarch64的做法,发现他们就没_PROCEDURE_LINKAGE_TABLE_, +++ 就不存在msym.minsym,然后认为从GOT entry读ifunc目标函数失败直接退出了。 +++ 5. 我想了想,_PROCEDURE_LINKAGE_TABLE_的存在没有意义,因为对plt stub +++ 的处理是有重定位R_LARCH_SOP_PUSH_PLT_PCREL由静态连接器一手操办。 +++ 所以就把_PROCEDURE_LINKAGE_TABLE_去了吧。 */ +++#define elf_backend_plt_alignment 4 +++#define elf_backend_can_gc_sections 1 +++//#define elf_backend_can_refcount 1 +++#define elf_backend_want_got_sym 1 +++ +++/* .got的第一项预留。我们约定.got的第一项为.dynamic的连接时地址(如果有) */ +++#define elf_backend_got_header_size (GOT_ENTRY_SIZE * 1) +++ +++#define elf_backend_want_dynrelro 1 +++//#define elf_backend_rela_normal 1 +++//#define elf_backend_default_execstack 0 +++ +++/* Generate a PLT header. */ +++ +++static void +++loongarch_make_plt_header (bfd_vma got_plt_addr, +++ bfd_vma plt_header_addr, +++ uint32_t *entry) +++{ +++ int64_t pcrel = got_plt_addr - plt_header_addr; +++ int64_t hi = (pcrel & 0x800? 1 : 0) + (pcrel >> 12); +++ int64_t lo = pcrel & 0xfff; +++ if ((hi >> 19) != 0 && (hi >> 19) != -1) +++ abort ();//overflow +++ +++ /* pcaddu12i $t2, %hi(%pcrel(.got.plt)) +++ sub.[wd] $t1, $t1, $t3 +++ ld.[wd] $t3, $t2, %lo(%pcrel(.got.plt)) # _dl_runtime_resolve +++ addi.[wd] $t1, $t1, -(PLT_HEADER_SIZE + 12) + 4 +++ addi.[wd] $t0, $t2, %lo(%pcrel(.got.plt)) +++ srli.[wd] $t1, $t1, log2(16 / GOT_ENTRY_SIZE) +++ ld.[wd] $t0, $t0, GOT_ENTRY_SIZE +++ jirl $r0, $t3, 0 */ +++ +++ if (GOT_ENTRY_SIZE == 8) +++ { +++ entry[0] = 0x1c00000e +++ | (hi & 0xfffff) << 5; +++ entry[1] = 0x0011bdad; +++ entry[2] = 0x28c001cf +++ | (lo & 0xfff) << 10; +++ entry[3] = 0x02c001ad +++ | ((-(PLT_HEADER_SIZE + 12) + 4) & 0xfff) << 10; +++ entry[4] = 0x02c001cc +++ | (lo & 0xfff) << 10; +++ entry[5] = 0x004501ad +++ | (4 - LARCH_ELF_LOG_WORD_BYTES) << 10; +++ entry[6] = 0x28c0018c +++ | GOT_ENTRY_SIZE << 10; +++ entry[7] = 0x4c0001e0; +++ } +++ else +++ { +++ entry[0] = 0x1c00000e +++ | (hi & 0xfffff) << 5; +++ entry[1] = 0x00113dad; +++ entry[2] = 0x288001cf +++ | (lo & 0xfff) << 10; +++ entry[3] = 0x028001ad +++ | ((-(PLT_HEADER_SIZE + 12)) & 0xfff) << 10; +++ entry[4] = 0x028001cc +++ | (lo & 0xfff) << 10; +++ entry[5] = 0x004481ad +++ | (4 - LARCH_ELF_LOG_WORD_BYTES) << 10; +++ entry[6] = 0x2880018c +++ | GOT_ENTRY_SIZE << 10; +++ entry[7] = 0x4c0001e0; +++ } +++} +++ +++/* Generate a PLT entry. */ +++ +++static void +++loongarch_make_plt_entry (bfd_vma got_plt_entry_addr, +++ bfd_vma plt_entry_addr, +++ uint32_t *entry) +++{ +++ int64_t pcrel = got_plt_entry_addr - plt_entry_addr; +++ int64_t hi = (pcrel & 0x800? 1 : 0) + (pcrel >> 12); +++ int64_t lo = pcrel & 0xfff; +++ if ((hi >> 19) != 0 && (hi >> 19) != -1) +++ abort ();//overflow +++ +++ /* pcaddu12i $t3, %hi(%pcrel(.got.plt entry)) +++ ld.[wd] $t3, $t3, %lo(%pcrel(.got.plt entry)) +++ jirl $t1, $t3, 0 +++ addi $r0, $r0, 0 */ +++ +++ entry[0] = 0x1c00000f +++ | (hi & 0xfffff) << 5; +++ entry[1] = (GOT_ENTRY_SIZE == 8? 0x28c001ef : 0x288001ef) +++ | (lo & 0xfff) << 10; +++ //entry[2] = 0x4c0001ed; /* jirl $r13, $15, 0 */ +++ //entry[3] = 0x03400000; /* nop */ +++ //entry[2] = 0x1800002d; /* pcaddi $13, 4 */ +++ entry[2] = 0x1c00000d; /* pcaddu12i $13, 4 */ +++ entry[3] = 0x4c0001e0; /* jirl $r0, $15, 0 */ +++} +++ +++/* Create an entry in an Loongarch ELF linker hash table. */ +++ +++static struct bfd_hash_entry * +++link_hash_newfunc (struct bfd_hash_entry *entry, +++ struct bfd_hash_table *table, const char *string) +++{ +++ /* Allocate the structure if it has not already been allocated by a +++ subclass. */ +++ if (entry == NULL) +++ { +++ entry = bfd_hash_allocate +++ (table, sizeof (struct loongarch_elf_link_hash_entry)); +++ if (entry == NULL) +++ return entry; +++ } +++ +++ /* Call the allocation method of the superclass. */ +++ entry = _bfd_elf_link_hash_newfunc (entry, table, string); +++ if (entry != NULL) +++ { +++ struct loongarch_elf_link_hash_entry *eh; +++ +++ eh = (struct loongarch_elf_link_hash_entry *) entry; +++ eh->dyn_relocs = NULL; +++ eh->tls_type = GOT_UNKNOWN; +++ } +++ +++ return entry; +++} +++ +++/* Compute a hash of a local hash entry. We use elf_link_hash_entry +++ for local symbol so that we can handle local STT_GNU_IFUNC symbols +++ as global symbol. We reuse indx and dynstr_index for local symbol +++ hash since they aren't used by global symbols in this backend. */ +++ +++static hashval_t +++elfNN_loongarch_local_htab_hash (const void *ptr) +++{ +++ struct elf_link_hash_entry *h +++ = (struct elf_link_hash_entry *) ptr; +++ return ELF_LOCAL_SYMBOL_HASH (h->indx, h->dynstr_index); +++} +++ +++/* Compare local hash entries. */ +++ +++static int +++elfNN_loongarch_local_htab_eq (const void *ptr1, const void *ptr2) +++{ +++ struct elf_link_hash_entry *h1 +++ = (struct elf_link_hash_entry *) ptr1; +++ struct elf_link_hash_entry *h2 +++ = (struct elf_link_hash_entry *) ptr2; +++ +++ return h1->indx == h2->indx && h1->dynstr_index == h2->dynstr_index; +++} +++ +++/* Find and/or create a hash entry for local symbol. */ +++static struct elf_link_hash_entry * +++elfNN_loongarch_get_local_sym_hash (struct loongarch_elf_link_hash_table *htab, +++ bfd *abfd, const Elf_Internal_Rela *rel, +++ bfd_boolean create) +++{ +++ struct loongarch_elf_link_hash_entry e, *ret; +++ asection *sec = abfd->sections; +++ hashval_t h = ELF_LOCAL_SYMBOL_HASH (sec->id, ELFNN_R_SYM (rel->r_info)); +++ void **slot; +++ +++ e.elf.indx = sec->id; +++ e.elf.dynstr_index = ELFNN_R_SYM (rel->r_info); +++ slot = htab_find_slot_with_hash +++ (htab->loc_hash_table, &e, h, create ? INSERT : NO_INSERT); +++ +++ if (!slot) +++ return NULL; +++ +++ if (*slot) +++ { +++ ret = (struct loongarch_elf_link_hash_entry *) *slot; +++ return &ret->elf; +++ } +++ +++ ret = (struct loongarch_elf_link_hash_entry *) +++ objalloc_alloc ((struct objalloc *) htab->loc_hash_memory, +++ sizeof (struct loongarch_elf_link_hash_entry)); +++ if (ret) +++ { +++ memset (ret, 0, sizeof (*ret)); +++ ret->elf.indx = sec->id; +++ ret->elf.pointer_equality_needed = 0; +++ ret->elf.dynstr_index = ELFNN_R_SYM (rel->r_info); +++ ret->elf.dynindx = -1; +++ ret->elf.needs_plt = 0; +++ ret->elf.plt.refcount = -1; +++ ret->elf.got.refcount = -1; +++ ret->elf.def_dynamic = 0; +++ ret->elf.def_regular = 1; +++ ret->elf.ref_dynamic = 0; /* this should be always 0 for local */ +++ ret->elf.ref_regular = 0; +++ ret->elf.forced_local = 1; +++ ret->elf.root.type = bfd_link_hash_defined; +++ *slot = ret; +++ } +++ return &ret->elf; +++} +++ +++/* Destroy an Loongarch elf linker hash table. */ +++ +++static void +++elfNN_loongarch_link_hash_table_free (bfd *obfd) +++{ +++ struct loongarch_elf_link_hash_table *ret +++ = (struct loongarch_elf_link_hash_table *) obfd->link.hash; +++ +++ if (ret->loc_hash_table) +++ htab_delete (ret->loc_hash_table); +++ if (ret->loc_hash_memory) +++ objalloc_free ((struct objalloc *) ret->loc_hash_memory); +++ +++ _bfd_elf_link_hash_table_free (obfd); +++} +++ +++/* Create a Loongarch ELF linker hash table. */ +++ +++static struct bfd_link_hash_table * +++loongarch_elf_link_hash_table_create (bfd *abfd) +++{ +++ struct loongarch_elf_link_hash_table *ret; +++ bfd_size_type amt = sizeof (struct loongarch_elf_link_hash_table); +++ +++ ret = (struct loongarch_elf_link_hash_table *) bfd_zmalloc (amt); +++ if (ret == NULL) +++ return NULL; +++ +++ if (!_bfd_elf_link_hash_table_init (&ret->elf, abfd, link_hash_newfunc, +++ sizeof (struct loongarch_elf_link_hash_entry), LARCH_ELF_DATA)) +++ { +++ free (ret); +++ return NULL; +++ } +++ +++ ret->max_alignment = MINUS_ONE; +++ +++ ret->loc_hash_table = htab_try_create (1024, +++ elfNN_loongarch_local_htab_hash, +++ elfNN_loongarch_local_htab_eq, +++ NULL); +++ ret->loc_hash_memory = objalloc_create (); +++ if (!ret->loc_hash_table || !ret->loc_hash_memory) +++ { +++ elfNN_loongarch_link_hash_table_free (abfd); +++ return NULL; +++ } +++ ret->elf.root.hash_table_free = elfNN_loongarch_link_hash_table_free; +++ +++ return &ret->elf.root; +++} +++ +++/* Merge backend specific data from an object file to the output +++ object file when linking. */ +++ +++static bfd_boolean +++_bfd_loongarch_elf_merge_private_bfd_data (bfd *ibfd, +++ struct bfd_link_info *info) +++{ +++ bfd *obfd = info->output_bfd; +++ flagword in_flags = elf_elfheader (ibfd)->e_flags; +++ flagword out_flags = elf_elfheader (obfd)->e_flags; +++ +++ if (!is_loongarch_elf (ibfd) || !is_loongarch_elf (obfd)) +++ { +++ /* Make sure one of ibfd or obfd e_flags must be set. */ +++ /* FIXME: EF_LARCH_ABI_LP64 ? . */ +++ if (!is_loongarch_elf (ibfd) && !elf_flags_init (obfd)) +++ { +++ elf_flags_init (obfd) = TRUE; +++ elf_elfheader (obfd)->e_flags = EF_LARCH_ABI_LP64; +++ } +++ +++ if (!is_loongarch_elf (obfd) && !elf_flags_init (ibfd)) +++ { +++ elf_flags_init (ibfd) = TRUE; +++ elf_elfheader (ibfd)->e_flags = EF_LARCH_ABI_LP64; +++ } +++ +++ return TRUE; +++ } +++ +++ if (strcmp (bfd_get_target (ibfd), bfd_get_target (obfd)) != 0) +++ { +++ _bfd_error_handler +++ (_("%pB: ABI is incompatible with that of the selected emulation:\n" +++ " target emulation `%s' does not match `%s'"), +++ ibfd, bfd_get_target (ibfd), bfd_get_target (obfd)); +++ return FALSE; +++ } +++ +++ if (!_bfd_elf_merge_object_attributes (ibfd, info)) +++ return FALSE; +++ +++ if (!elf_flags_init (obfd)) +++ { +++ elf_flags_init (obfd) = TRUE; +++ elf_elfheader (obfd)->e_flags = in_flags; +++ return TRUE; +++ } +++ +++ /* Disallow linking different float ABIs. */ +++ if ((out_flags ^ in_flags) & EF_LARCH_ABI) +++ { +++ _bfd_error_handler +++ (_("%pB: can't link different ABI object."), ibfd); +++ goto fail; +++ } +++ +++ return TRUE; +++ +++fail: +++ bfd_set_error (bfd_error_bad_value); +++ return FALSE; +++} +++ +++/* Create the .got section. */ +++ +++static bfd_boolean +++loongarch_elf_create_got_section (bfd *abfd, struct bfd_link_info *info) +++{ +++ flagword flags; +++ asection *s, *s_got; +++ struct elf_link_hash_entry *h; +++ const struct elf_backend_data *bed = get_elf_backend_data (abfd); +++ struct elf_link_hash_table *htab = elf_hash_table (info); +++ +++ /* This function may be called more than once. */ +++ if (htab->sgot != NULL) +++ return TRUE; +++ +++ flags = bed->dynamic_sec_flags; +++ +++ s = bfd_make_section_anyway_with_flags +++ (abfd, bed->rela_plts_and_copies_p ? ".rela.got" : ".rel.got", +++ bed->dynamic_sec_flags | SEC_READONLY); +++ if (s == NULL +++ || !bfd_set_section_alignment (s, bed->s->log_file_align)) +++ return FALSE; +++ htab->srelgot = s; +++ +++ s = s_got = bfd_make_section_anyway_with_flags (abfd, ".got", flags); +++ if (s == NULL +++ || !bfd_set_section_alignment (s, bed->s->log_file_align)) +++ return FALSE; +++ htab->sgot = s; +++ +++ /* The first bit of the global offset table is the header. */ +++ s->size += bed->got_header_size; +++ +++ if (bed->want_got_plt) +++ { +++ s = bfd_make_section_anyway_with_flags (abfd, ".got.plt", flags); +++ if (s == NULL +++ || !bfd_set_section_alignment (s, bed->s->log_file_align)) +++ return FALSE; +++ htab->sgotplt = s; +++ +++ /* 相比_bfd_elf_create_got_section: +++ 一方面,RISCV似乎是希望.got.plt和.got都有header; +++ 而且_GLOBAL_OFFSET_TABLE_是.got的开头,而不是.got.plt的开头。 +++ 和公共部分需求有冲突。所以自己实现了 */ +++ +++ /* Reserve room for the header. */ +++ s->size = GOTPLT_HEADER_SIZE; +++ } +++ +++ if (bed->want_got_sym) +++ { +++ /* Define the symbol _GLOBAL_OFFSET_TABLE_ at the start of the .got +++ section. We don't do this in the linker script because we don't want +++ to define the symbol if we are not creating a global offset table. */ +++ h = _bfd_elf_define_linkage_sym (abfd, info, s_got, +++ "_GLOBAL_OFFSET_TABLE_"); +++ elf_hash_table (info)->hgot = h; +++ if (h == NULL) +++ return FALSE; +++ } +++ return TRUE; +++} +++ +++/* Create .plt, .rela.plt, .got, .got.plt, .rela.got, .dynbss, and +++ .rela.bss sections in DYNOBJ, and set up shortcuts to them in our +++ hash table. */ +++ +++static bfd_boolean +++loongarch_elf_create_dynamic_sections (bfd *dynobj, +++ struct bfd_link_info *info) +++{ +++ struct loongarch_elf_link_hash_table *htab; +++ +++ htab = loongarch_elf_hash_table (info); +++ BFD_ASSERT (htab != NULL); +++ +++ if (!loongarch_elf_create_got_section (dynobj, info)) +++ return FALSE; +++ +++ if (!_bfd_elf_create_dynamic_sections (dynobj, info)) +++ return FALSE; +++ +++ if (!bfd_link_pic (info)) +++ { +++ htab->sdyntdata = +++ bfd_make_section_anyway_with_flags (dynobj, ".tdata.dyn", +++ SEC_ALLOC | SEC_THREAD_LOCAL); +++ } +++ +++ if (!htab->elf.splt || !htab->elf.srelplt || !htab->elf.sdynbss +++ || (!bfd_link_pic (info) && (!htab->elf.srelbss || !htab->sdyntdata))) +++ abort (); +++ +++ return TRUE; +++} +++ +++static bfd_boolean +++loongarch_elf_record_tls_and_got_reference (bfd *abfd, +++ struct bfd_link_info *info, +++ struct elf_link_hash_entry *h, +++ unsigned long symndx, +++ char tls_type) +++{ +++ struct loongarch_elf_link_hash_table *htab = loongarch_elf_hash_table (info); +++ Elf_Internal_Shdr *symtab_hdr = &elf_tdata (abfd)->symtab_hdr; +++ +++ /* This is a global offset table entry for a local symbol. */ +++ if (elf_local_got_refcounts (abfd) == NULL) +++ { +++ bfd_size_type size = +++ symtab_hdr->sh_info * (sizeof (bfd_vma) + sizeof (tls_type)); +++ if (!(elf_local_got_refcounts (abfd) = bfd_zalloc (abfd, size))) +++ return FALSE; +++ _bfd_loongarch_elf_local_got_tls_type (abfd) +++ = (char *) (elf_local_got_refcounts (abfd) + symtab_hdr->sh_info); +++ } +++ +++ switch (tls_type) +++ { +++ case GOT_NORMAL: +++ case GOT_TLS_GD: +++ case GOT_TLS_IE: +++ /* need GOT */ +++ if (htab->elf.sgot == NULL +++ && !loongarch_elf_create_got_section (htab->elf.dynobj, info)) +++ return FALSE; +++ if (h) +++ { +++ if (h->got.refcount < 0) +++ h->got.refcount = 0; +++ h->got.refcount++; +++ } +++ else +++ elf_local_got_refcounts (abfd) [symndx] ++; +++ break; +++ case GOT_TLS_LE: +++ /* no need for GOT */ +++ break; +++ default: +++ _bfd_error_handler (_("%pB: Interl error: unreachable.")); +++ return FALSE; +++ } +++ +++ char *new_tls_type = &_bfd_loongarch_elf_tls_type (abfd, h, symndx); +++ *new_tls_type |= tls_type; +++ if ((*new_tls_type & GOT_NORMAL) && (*new_tls_type & ~GOT_NORMAL)) +++ { +++ _bfd_error_handler +++ (_("%pB: `%s' accessed both as normal and thread local symbol"), +++ abfd, h ? h->root.root.string : ""); +++ return FALSE; +++ } +++ +++ return TRUE; +++} +++ +++/* Look through the relocs for a section during the first phase, and +++ allocate space in the global offset table or procedure linkage +++ table. */ +++ +++static bfd_boolean +++loongarch_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, +++ asection *sec, const Elf_Internal_Rela *relocs) +++{ +++ struct loongarch_elf_link_hash_table *htab; +++ Elf_Internal_Shdr *symtab_hdr; +++ struct elf_link_hash_entry **sym_hashes; +++ const Elf_Internal_Rela *rel; +++ asection *sreloc = NULL; +++ +++ if (bfd_link_relocatable (info)) +++ return TRUE; +++ +++ htab = loongarch_elf_hash_table (info); +++ symtab_hdr = &elf_tdata (abfd)->symtab_hdr; +++ sym_hashes = elf_sym_hashes (abfd); +++ +++ if (htab->elf.dynobj == NULL) +++ htab->elf.dynobj = abfd; +++ +++ /* 这个函数的遍历每一个重定位,将一些信息归置到符号中。这之后的处理 +++ 都会通过遍历符号进行,根据符号中的信息来确定最终二进制文件的形态。 +++ 1.根据重定位类型记录那个符号是否需要GOT entry +++ 2.根据重定位类型记录那个符号的TLS引用模型 +++ 3.处理IFUNC +++ 4.等等 +++ */ +++ +++ for (rel = relocs; rel < relocs + sec->reloc_count; rel++) +++ { +++ unsigned int r_type; +++ unsigned int r_symndx; +++ struct elf_link_hash_entry *h; +++ Elf_Internal_Sym *isym = NULL; +++ +++ /* 意味着在dynamic_sections_created置位的情况下,这个重定位可能需要动态 +++ 连接器的帮助。如果是这样,我们会在动态重定位表中为其分配一个表项。 */ +++ int need_dynreloc; +++ +++ /* 意味着这个动态重定位仅需要符号的pcrel信息,即符号定义在自身模块内 +++ 及延伸出来的其他信息。如果是这样,我们就在连接时知道了这个重定位的值, +++ 就可以把这个动态重定位取消掉。 */ +++ int only_need_pcrel; +++ +++ r_symndx = ELFNN_R_SYM (rel->r_info); +++ r_type = ELFNN_R_TYPE (rel->r_info); +++ +++ if (r_symndx >= NUM_SHDR_ENTRIES (symtab_hdr)) +++ { +++ _bfd_error_handler +++ (_("%pB: bad symbol index: %d"), abfd, r_symndx); +++ return FALSE; +++ } +++ +++ if (r_symndx < symtab_hdr->sh_info) +++ { +++ /* A local symbol. */ +++ isym = bfd_sym_from_r_symndx (&htab->sym_cache, abfd, r_symndx); +++ if (isym == NULL) +++ return FALSE; +++ +++ if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC) +++ { +++ h = elfNN_loongarch_get_local_sym_hash (htab, abfd, rel, TRUE); +++ if (h == NULL) +++ return FALSE; +++ +++ h->type = STT_GNU_IFUNC; +++ h->ref_regular = 1; +++ } +++ else +++ h = NULL; +++ } +++ else +++ { +++ h = sym_hashes[r_symndx - symtab_hdr->sh_info]; +++ while (h->root.type == bfd_link_hash_indirect +++ || h->root.type == bfd_link_hash_warning) +++ h = (struct elf_link_hash_entry *) h->root.u.i.link; +++ } +++ +++ if (h && h->type == STT_GNU_IFUNC) +++ { +++ if (htab->elf.dynobj == NULL) +++ htab->elf.dynobj = abfd; +++ +++ if (!htab->elf.splt +++ && !_bfd_elf_create_ifunc_sections (htab->elf.dynobj, info)) +++ /* If '.plt' not represent, create '.iplt' to deal with ifunc. */ +++ return FALSE; +++ +++ if (h->plt.refcount < 0) +++ h->plt.refcount = 0; +++ h->plt.refcount++; +++ h->needs_plt = 1; +++ +++ elf_tdata (info->output_bfd)->has_gnu_osabi +++ |= elf_gnu_osabi_ifunc; +++ } +++ +++ need_dynreloc = 0; +++ only_need_pcrel = 0; +++ switch (r_type) +++ { +++ case R_LARCH_SOP_PUSH_GPREL: +++ if (!loongarch_elf_record_tls_and_got_reference +++ (abfd, info, h, r_symndx, GOT_NORMAL)) +++ return FALSE; +++ break; +++ +++ case R_LARCH_SOP_PUSH_TLS_GD: +++ if (!loongarch_elf_record_tls_and_got_reference +++ (abfd, info, h, r_symndx, GOT_TLS_GD)) +++ return FALSE; +++ break; +++ +++ case R_LARCH_SOP_PUSH_TLS_GOT: +++ if (bfd_link_pic (info)) +++ /* may fail for lazy-bind */ +++ info->flags |= DF_STATIC_TLS; +++ +++ if (!loongarch_elf_record_tls_and_got_reference +++ (abfd, info, h, r_symndx, GOT_TLS_IE)) +++ return FALSE; +++ break; +++ +++ case R_LARCH_SOP_PUSH_TLS_TPREL: +++ if (!bfd_link_executable (info)) +++ return FALSE; +++ +++ info->flags |= DF_STATIC_TLS; +++ +++ if (!loongarch_elf_record_tls_and_got_reference +++ (abfd, info, h, r_symndx, GOT_TLS_LE)) +++ return FALSE; +++ break; +++ +++ case R_LARCH_SOP_PUSH_ABSOLUTE: +++ if (h != NULL) +++ /* If this reloc is in a read-only section, we might +++ need a copy reloc. We can't check reliably at this +++ stage whether the section is read-only, as input +++ sections have not yet been mapped to output sections. +++ Tentatively set the flag for now, and correct in +++ adjust_dynamic_symbol. */ +++ /* 这个flag的本质是关注对一个符号的引用能否被动态连接器改变。 +++ 比如la.pcrel,在连接时会将符号的pc相对偏移量写入指令立即数; +++ 而代码段是只读的,动态连接器无法改动指令,这时,那个la只能引用 +++ local的那个符号的定义了,无法被动态连接器改变。 +++ 而使用got表的话,因为got entry可以被动态连接器改变,因此可以改变 +++ la到底哪个模块中的符号。 +++ 动态库里的符号定义可能被可执行文件中的符号定义覆盖,由此,动态库 +++ 中对符号的引用必须可以被动态连接器改变; +++ 而如果在可执行文件中la.pcrel一个动态库中的对象,按常理来说,如果 +++ 不走got表,这个引用是错误的。但如果我们真的把这个符号定义在 +++ 可执行文件中,而将动态库中对象的初始值复制到可执行文件中 +++ (R_LARCH_COPY),这其实等效于引用动态库中的对象了。 +++ 由此,如果某个重定位一旦可能不被动态链接器控制,这个flag被置位, +++ 接下来的处理会根据情况加上R_LARCH_COPY重定位。这样,我们也只能 +++ 在可执行文件中做这件事;动态库中的R_LARCH_COPY是很奇怪的。 */ +++ h->non_got_ref = 1; +++ break; +++ +++ case R_LARCH_SOP_PUSH_PCREL: +++ if (h != NULL) +++ { +++ h->non_got_ref = 1; +++ +++ /* We try to create PLT stub for all non-local function. */ +++ if (h->plt.refcount < 0) +++ h->plt.refcount = 0; +++ h->plt.refcount++; +++ } +++ break; +++ +++ case R_LARCH_SOP_PUSH_PLT_PCREL: +++ /* This symbol requires a procedure linkage table entry. We +++ actually build the entry in adjust_dynamic_symbol, +++ because this might be a case of linking PIC code without +++ linking in any dynamic objects, in which case we don't +++ need to generate a procedure linkage table after all. */ +++ if (h != NULL) +++ { +++ h->needs_plt = 1; +++ if (h->plt.refcount < 0) +++ h->plt.refcount = 0; +++ h->plt.refcount++; +++ } +++ break; +++ +++ case R_LARCH_TLS_DTPREL32: +++ case R_LARCH_TLS_DTPREL64: +++ need_dynreloc = 1; +++ only_need_pcrel = 1; +++ break; +++ +++ case R_LARCH_JUMP_SLOT: +++ case R_LARCH_32: +++ case R_LARCH_64: +++ need_dynreloc = 1; +++ +++ /* If resolved symbol is defined in this object, +++ 1. Under pie, the symbol is known. We convert it +++ into R_LARCH_RELATIVE and need load-addr still. +++ 2. Under pde, the symbol is known and we can discard R_LARCH_NN. +++ 3. Under dll, R_LARCH_NN can't be changed normally, since +++ its defination could be covered by the one in executable. +++ For symbolic, we convert it into R_LARCH_RELATIVE. +++ Thus, only under pde, it needs pcrel only. We discard it. */ +++ only_need_pcrel = bfd_link_pde (info); +++ +++ if (h != NULL) +++ h->non_got_ref = 1; +++ break; +++ +++ case R_LARCH_GNU_VTINHERIT: +++ if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset)) +++ return FALSE; +++ break; +++ +++ case R_LARCH_GNU_VTENTRY: +++ if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend)) +++ return FALSE; +++ break; +++ +++ default: +++ break; +++ } +++ +++ /* Record some info for sizing and allocating dynamic entry */ +++ if (need_dynreloc && (sec->flags & SEC_ALLOC)) +++ { +++ /* When creating a shared object, we must copy these +++ relocs into the output file. We create a reloc +++ section in dynobj and make room for the reloc. */ +++ struct elf_dyn_relocs *p; +++ struct elf_dyn_relocs **head; +++ +++ if (sreloc == NULL) +++ { +++ sreloc = _bfd_elf_make_dynamic_reloc_section +++ (sec, htab->elf.dynobj, LARCH_ELF_LOG_WORD_BYTES, +++ abfd, /*rela?*/ TRUE); +++ +++ if (sreloc == NULL) +++ return FALSE; +++ } +++ +++ /* If this is a global symbol, we count the number of +++ relocations we need for this symbol. */ +++ if (h != NULL) +++ head = &((struct loongarch_elf_link_hash_entry *) h)->dyn_relocs; +++ else +++ { +++ /* Track dynamic relocs needed for local syms too. +++ We really need local syms available to do this +++ easily. Oh well. */ +++ +++ asection *s; +++ void *vpp; +++ +++ s = bfd_section_from_elf_index (abfd, isym->st_shndx); +++ if (s == NULL) +++ s = sec; +++ +++ vpp = &elf_section_data (s)->local_dynrel; +++ head = (struct elf_dyn_relocs **) vpp; +++ } +++ +++ p = *head; +++ if (p == NULL || p->sec != sec) +++ { +++ bfd_size_type amt = sizeof *p; +++ p = (struct elf_dyn_relocs *) bfd_alloc (htab->elf.dynobj, amt); +++ if (p == NULL) +++ return FALSE; +++ p->next = *head; +++ *head = p; +++ p->sec = sec; +++ p->count = 0; +++ p->pc_count = 0; +++ } +++ +++ p->count++; +++ p->pc_count += only_need_pcrel; +++ } +++ } +++ +++ return TRUE; +++} +++ +++/* Find dynamic relocs for H that apply to read-only sections. */ +++ +++static asection * +++readonly_dynrelocs (struct elf_link_hash_entry *h) +++{ +++ struct elf_dyn_relocs *p; +++ +++ for (p = loongarch_elf_hash_entry (h)->dyn_relocs; p != NULL; p = p->next) +++ { +++ asection *s = p->sec->output_section; +++ +++ if (s != NULL && (s->flags & SEC_READONLY) != 0) +++ return p->sec; +++ } +++ return NULL; +++} +++ +++/* Adjust a symbol defined by a dynamic object and referenced by a +++ regular object. The current definition is in some section of the +++ dynamic object, but we're not including those sections. We have to +++ change the definition to something the rest of the link can +++ understand. */ +++static bfd_boolean +++loongarch_elf_adjust_dynamic_symbol (struct bfd_link_info *info, +++ struct elf_link_hash_entry *h) +++{ +++ struct loongarch_elf_link_hash_table *htab; +++ struct loongarch_elf_link_hash_entry * eh; +++ bfd *dynobj; +++ asection *s, *srel; +++ +++ htab = loongarch_elf_hash_table (info); +++ BFD_ASSERT (htab != NULL); +++ +++ dynobj = htab->elf.dynobj; +++ +++ /* Make sure we know what is going on here. */ +++ BFD_ASSERT (dynobj != NULL +++ && (h->needs_plt +++ || h->type == STT_GNU_IFUNC +++ || h->is_weakalias +++ || (h->def_dynamic +++ && h->ref_regular +++ && !h->def_regular))); +++ +++ /* If this is a function, put it in the procedure linkage table. We +++ will fill in the contents of the procedure linkage table later +++ (although we could actually do it here). */ +++ if (h->type == STT_FUNC || h->type == STT_GNU_IFUNC || h->needs_plt) +++ { +++ if (h->plt.refcount < 0 +++ || (h->type != STT_GNU_IFUNC +++ && (SYMBOL_REFERENCES_LOCAL (info, h) +++ || (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT +++ && h->root.type == bfd_link_hash_undefweak)))) +++ { +++ /* This case can occur if we saw a R_LARCH_SOP_PUSH_PLT_PCREL reloc +++ in an input file, but the symbol was never referred to by a +++ dynamic object, or if all references were garbage collected. +++ In such a case, we don't actually need to build a PLT entry. */ +++ h->plt.offset = MINUS_ONE; +++ h->needs_plt = 0; +++ } +++ else +++ h->needs_plt = 1; +++ +++ return TRUE; +++ } +++ else +++ h->plt.offset = MINUS_ONE; +++ +++ /* If this is a weak symbol, and there is a real definition, the +++ processor independent code will have arranged for us to see the +++ real definition first, and we can just use the same value. */ +++ if (h->is_weakalias) +++ { +++ struct elf_link_hash_entry *def = weakdef (h); +++ BFD_ASSERT (def->root.type == bfd_link_hash_defined); +++ h->root.u.def.section = def->root.u.def.section; +++ h->root.u.def.value = def->root.u.def.value; +++ return TRUE; +++ } +++ +++ /* This is a reference to a symbol defined by a dynamic object which +++ is not a function. */ +++ +++ /* If we are creating a shared library, we must presume that the +++ only references to the symbol are via the global offset table. +++ For such cases we need not do anything here; the relocations will +++ be handled correctly by relocate_section. */ +++ if (bfd_link_dll (info)) +++ return TRUE; +++ +++ /* If there are no references to this symbol that do not use the +++ GOT, we don't need to generate a copy reloc. */ +++ if (!h->non_got_ref) +++ return TRUE; +++ +++ /* If -z nocopyreloc was given, we won't generate them either. */ +++ if (info->nocopyreloc) +++ { +++ h->non_got_ref = 0; +++ return TRUE; +++ } +++ +++ /* If we don't find any dynamic relocs in read-only sections, then +++ we'll be keeping the dynamic relocs and avoiding the copy reloc. */ +++ if (!readonly_dynrelocs (h)) +++ { +++ h->non_got_ref = 0; +++ return TRUE; +++ } +++ +++ /* We must allocate the symbol in our .dynbss section, which will +++ become part of the .bss section of the executable. There will be +++ an entry for this symbol in the .dynsym section. The dynamic +++ object will contain position independent code, so all references +++ from the dynamic object to this symbol will go through the global +++ offset table. The dynamic linker will use the .dynsym entry to +++ determine the address it must put in the global offset table, so +++ both the dynamic object and the regular object will refer to the +++ same memory location for the variable. */ +++ +++ /* We must generate a R_LARCH_COPY reloc to tell the dynamic linker +++ to copy the initial value out of the dynamic object and into the +++ runtime process image. We need to remember the offset into the +++ .rel.bss section we are going to use. */ +++ eh = (struct loongarch_elf_link_hash_entry *) h; +++ if (eh->tls_type & ~GOT_NORMAL) +++ { +++ s = htab->sdyntdata; +++ srel = htab->elf.srelbss; +++ } +++ else +++ if ((h->root.u.def.section->flags & SEC_READONLY) != 0) +++ { +++ s = htab->elf.sdynrelro; +++ srel = htab->elf.sreldynrelro; +++ } +++ else +++ { +++ s = htab->elf.sdynbss; +++ srel = htab->elf.srelbss; +++ } +++ if ((h->root.u.def.section->flags & SEC_ALLOC) != 0 && h->size != 0) +++ { +++ srel->size += sizeof (ElfNN_External_Rela); +++ h->needs_copy = 1; +++ } +++ +++ return _bfd_elf_adjust_dynamic_copy (info, h, s); +++} +++ +++ +++/* Allocate space in .plt, .got and associated reloc sections for +++ dynamic relocs. */ +++ +++static bfd_boolean +++allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) +++{ +++ struct bfd_link_info *info; +++ struct loongarch_elf_link_hash_table *htab; +++ struct loongarch_elf_link_hash_entry *eh; +++ struct elf_dyn_relocs *p; +++ +++ if (h->root.type == bfd_link_hash_indirect) +++ return TRUE; +++ +++ eh = (struct loongarch_elf_link_hash_entry *) h; +++ info = (struct bfd_link_info *) inf; +++ htab = loongarch_elf_hash_table (info); +++ BFD_ASSERT (htab != NULL); +++ +++ /* 在这里针对符号对.got .iplt .plt的扩充和后续elf_finish_dynamic_symbol补充 +++ 内容对照;WILL_CALL_FINISH_DYNAMIC_SYMBOL似乎指的是这个符号在将来会不会被 +++ finish_dynamic_symbol调用。 +++ a. 对于非IFUNC符号,被allocate_dynrelocs照顾到的符号h要保证在链接后期被 +++ elf_finish_dynamic_symbol调用 +++ b. STT_GNU_IFUNC符号一定走plt,但是对于那些local转化为h的符号,默认是不会 +++ 被调用allocate_dynrelocs和elf_finish_dynamic_symbol的,要手动遍历 +++ 这些符号来调用这两个函数,从而为它们分配plt stub; +++ 而WILL_CALL_FINISH_DYNAMIC_SYMBOL返回false,因此下面的逻辑都是 +++ WILL_CALL_FINISH_DYNAMIC_SYMBOL和对IFUNC的判断配合起来。 */ +++ +++ do +++ { +++ asection *plt, *gotplt, *relplt; +++ +++ if (!h->needs_plt) +++ break; +++ +++ h->needs_plt = 0; +++ +++ if (htab->elf.splt) +++ { +++ if (h->dynindx == -1 && !h->forced_local +++ && !bfd_elf_link_record_dynamic_symbol (info, h)) +++ return FALSE; +++ +++ if (!WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, bfd_link_pic (info), h) +++ && h->type != STT_GNU_IFUNC) +++ break; +++ +++ plt = htab->elf.splt; +++ gotplt = htab->elf.sgotplt; +++ relplt = htab->elf.srelplt; +++ } +++ else if (htab->elf.iplt) +++ { +++ /* .iplt only for IFUNC */ +++ if (h->type != STT_GNU_IFUNC) +++ break; +++ +++ plt = htab->elf.iplt; +++ gotplt = htab->elf.igotplt; +++ relplt = htab->elf.irelplt; +++ } +++ else +++ break; +++ +++ if (plt->size == 0) +++ plt->size = PLT_HEADER_SIZE; +++ +++ h->plt.offset = plt->size; +++ plt->size += PLT_ENTRY_SIZE; +++ gotplt->size += GOT_ENTRY_SIZE; +++ relplt->size += sizeof (ElfNN_External_Rela); +++ +++ h->needs_plt = 1; +++ } +++ while (0); +++ +++ if (!h->needs_plt) +++ h->plt.offset = MINUS_ONE; +++ +++ if (0 < h->got.refcount) +++ { +++ asection *s; +++ bfd_boolean dyn; +++ int tls_type = loongarch_elf_hash_entry (h)->tls_type; +++ +++ /* Make sure this symbol is output as a dynamic symbol. +++ Undefined weak syms won't yet be marked as dynamic. */ +++ if (h->dynindx == -1 && !h->forced_local +++ && !bfd_elf_link_record_dynamic_symbol (info, h)) +++ return FALSE; +++ +++ s = htab->elf.sgot; +++ h->got.offset = s->size; +++ dyn = htab->elf.dynamic_sections_created; +++ if (tls_type & (GOT_TLS_GD | GOT_TLS_IE)) +++ { +++ /* TLS_GD needs two dynamic relocs and two GOT slots. */ +++ if (tls_type & GOT_TLS_GD) +++ { +++ s->size += 2 * GOT_ENTRY_SIZE; +++ htab->elf.srelgot->size += 2 * sizeof (ElfNN_External_Rela); +++ } +++ +++ /* TLS_IE needs one dynamic reloc and one GOT slot. */ +++ if (tls_type & GOT_TLS_IE) +++ { +++ s->size += GOT_ENTRY_SIZE; +++ htab->elf.srelgot->size += sizeof (ElfNN_External_Rela); +++ } +++ } +++ else +++ { +++ s->size += GOT_ENTRY_SIZE; +++ if ((WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, bfd_link_pic (info), h) +++ && !UNDEFWEAK_NO_DYNAMIC_RELOC (info, h)) +++ || h->type == STT_GNU_IFUNC) +++ htab->elf.srelgot->size += sizeof (ElfNN_External_Rela); +++ } +++ } +++ else +++ h->got.offset = MINUS_ONE; +++ +++ if (eh->dyn_relocs == NULL) +++ return TRUE; +++ +++ /* 如果某些函数未被定义,SYMBOL_CALLS_LOCAL返回1; +++ 而SYMBOL_REFERENCES_LOCAL返回0。 +++ 似乎是因为未定义的函数可以有plt从而将其转化为local的。 */ +++ if (SYMBOL_REFERENCES_LOCAL (info, h)) +++ { +++ struct elf_dyn_relocs **pp; +++ +++ for (pp = &eh->dyn_relocs; (p = *pp) != NULL; ) +++ { +++ p->count -= p->pc_count; +++ p->pc_count = 0; +++ if (p->count == 0) +++ *pp = p->next; +++ else +++ pp = &p->next; +++ } +++ } +++ +++ if (h->root.type == bfd_link_hash_undefweak) +++ { +++ if (UNDEFWEAK_NO_DYNAMIC_RELOC (info, h)) +++ eh->dyn_relocs = NULL; +++ else if (h->dynindx == -1 && !h->forced_local +++ /* Make sure this symbol is output as a dynamic symbol. +++ Undefined weak syms won't yet be marked as dynamic. */ +++ && !bfd_elf_link_record_dynamic_symbol (info, h)) +++ return FALSE; +++ } +++ +++ for (p = eh->dyn_relocs; p != NULL; p = p->next) +++ { +++ asection *sreloc = elf_section_data (p->sec)->sreloc; +++ sreloc->size += p->count * sizeof (ElfNN_External_Rela); +++ } +++ +++ return TRUE; +++} +++ +++static bfd_boolean +++elfNN_loongarch_allocate_local_dynrelocs (void **slot, void *inf) +++{ +++ struct elf_link_hash_entry *h +++ = (struct elf_link_hash_entry *) *slot; +++ +++ if (!h->def_regular +++ || !h->ref_regular +++ || !h->forced_local +++ || h->root.type != bfd_link_hash_defined) +++ abort (); +++ +++ return allocate_dynrelocs (h, inf); +++} +++ +++/* Set DF_TEXTREL if we find any dynamic relocs that apply to +++ read-only sections. */ +++ +++static bfd_boolean +++maybe_set_textrel (struct elf_link_hash_entry *h, void *info_p) +++{ +++ asection *sec; +++ +++ if (h->root.type == bfd_link_hash_indirect) +++ return TRUE; +++ +++ sec = readonly_dynrelocs (h); +++ if (sec != NULL) +++ { +++ struct bfd_link_info *info = (struct bfd_link_info *) info_p; +++ +++ info->flags |= DF_TEXTREL; +++ info->callbacks->minfo ( +++ _("%pB: dynamic relocation against `%pT' in read-only section `%pA'\n"), +++ sec->owner, h->root.root.string, sec); +++ +++ /* Not an error, just cut short the traversal. */ +++ return FALSE; +++ } +++ return TRUE; +++} +++ +++static bfd_boolean +++loongarch_elf_size_dynamic_sections (bfd *output_bfd, +++ struct bfd_link_info *info) +++{ +++ struct loongarch_elf_link_hash_table *htab; +++ bfd *dynobj; +++ asection *s; +++ bfd *ibfd; +++ +++ htab = loongarch_elf_hash_table (info); +++ BFD_ASSERT (htab != NULL); +++ dynobj = htab->elf.dynobj; +++ BFD_ASSERT (dynobj != NULL); +++ +++ if (htab->elf.dynamic_sections_created) +++ { +++ /* Set the contents of the .interp section to the interpreter. */ +++ if (bfd_link_executable (info) && !info->nointerp) +++ { +++ const char *interpreter; +++ flagword flags = elf_elfheader (output_bfd)->e_flags; +++ s = bfd_get_linker_section (dynobj, ".interp"); +++ BFD_ASSERT (s != NULL); +++ if ((flags & EF_LARCH_ABI) == EF_LARCH_ABI_LP32) +++ interpreter = "/lib32/ld.so.1"; +++ else if ((flags & EF_LARCH_ABI) == EF_LARCH_ABI_LP64) +++ interpreter = "/lib64/ld.so.1"; +++ else +++ interpreter = "/lib/ld.so.1"; +++ s->contents = (unsigned char *) interpreter; +++ s->size = strlen (interpreter) + 1; +++ } +++ } +++ +++ /* Set up .got offsets for local syms, and space for local dynamic +++ relocs. */ +++ for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) +++ { +++ bfd_signed_vma *local_got; +++ bfd_signed_vma *end_local_got; +++ char *local_tls_type; +++ bfd_size_type locsymcount; +++ Elf_Internal_Shdr *symtab_hdr; +++ asection *srel; +++ +++ if (!is_loongarch_elf (ibfd)) +++ continue; +++ +++ for (s = ibfd->sections; s != NULL; s = s->next) +++ { +++ struct elf_dyn_relocs *p; +++ +++ for (p = elf_section_data (s)->local_dynrel; p != NULL; p = p->next) +++ { +++ p->count -= p->pc_count; +++ if (!bfd_is_abs_section (p->sec) +++ && bfd_is_abs_section (p->sec->output_section)) +++ { +++ /* Input section has been discarded, either because +++ it is a copy of a linkonce section or due to +++ linker script /DISCARD/, so we'll be discarding +++ the relocs too. */ +++ } +++ else if (0 < p->count) +++ { +++ srel = elf_section_data (p->sec)->sreloc; +++ srel->size += p->count * sizeof (ElfNN_External_Rela); +++ if ((p->sec->output_section->flags & SEC_READONLY) != 0) +++ info->flags |= DF_TEXTREL; +++ } +++ } +++ } +++ +++ local_got = elf_local_got_refcounts (ibfd); +++ if (!local_got) +++ continue; +++ +++ symtab_hdr = &elf_symtab_hdr (ibfd); +++ locsymcount = symtab_hdr->sh_info; +++ end_local_got = local_got + locsymcount; +++ local_tls_type = _bfd_loongarch_elf_local_got_tls_type (ibfd); +++ s = htab->elf.sgot; +++ srel = htab->elf.srelgot; +++ for (; local_got < end_local_got; ++local_got, ++local_tls_type) +++ { +++ if (0 < *local_got) +++ { +++ *local_got = s->size; +++ s->size += GOT_ENTRY_SIZE; +++ +++ if (*local_tls_type & GOT_TLS_GD) +++ s->size += GOT_ENTRY_SIZE; +++ +++ if (bfd_link_pic (info) /* R_LARCH_RELATIVE */ +++ || (*local_tls_type & +++ (GOT_TLS_GD /* R_LARCH_TLS_DTPRELNN */ +++ | GOT_TLS_IE /* R_LARCH_TLS_TPRELNN */))) +++ srel->size += sizeof (ElfNN_External_Rela); +++ } +++ else +++ *local_got = MINUS_ONE; +++ } +++ } +++ +++ /* Allocate global sym .plt and .got entries, and space for global +++ sym dynamic relocs. */ +++ elf_link_hash_traverse (&htab->elf, allocate_dynrelocs, info); +++ /* Allocate .plt and .got entries, and space for local ifunc symbols. */ +++ htab_traverse (htab->loc_hash_table, +++ elfNN_loongarch_allocate_local_dynrelocs, +++ info); +++ +++ /* Don't allocate .got.plt section if there are no PLT. */ +++ if (htab->elf.sgotplt +++ && htab->elf.sgotplt->size == GOTPLT_HEADER_SIZE +++ && (htab->elf.splt == NULL +++ || htab->elf.splt->size == 0)) +++ htab->elf.sgotplt->size = 0; +++ +++ /* The check_relocs and adjust_dynamic_symbol entry points have +++ determined the sizes of the various dynamic sections. Allocate +++ memory for them. */ +++ for (s = dynobj->sections; s != NULL; s = s->next) +++ { +++ if ((s->flags & SEC_LINKER_CREATED) == 0) +++ continue; +++ +++ if (s == htab->elf.splt +++ || s == htab->elf.iplt +++ || s == htab->elf.sgot +++ || s == htab->elf.sgotplt +++ || s == htab->elf.igotplt +++ || s == htab->elf.sdynbss +++ || s == htab->elf.sdynrelro) +++ { +++ /* Strip this section if we don't need it; see the +++ comment below. */ +++ } +++ else if (strncmp (s->name, ".rela", 5) == 0) +++ { +++ if (s->size != 0) +++ { +++ /* We use the reloc_count field as a counter if we need +++ to copy relocs into the output file. */ +++ s->reloc_count = 0; +++ } +++ } +++ else +++ { +++ /* It's not one of our sections. */ +++ continue; +++ } +++ +++ if (s->size == 0) +++ { +++ /* If we don't need this section, strip it from the +++ output file. This is mostly to handle .rela.bss and +++ .rela.plt. We must create both sections in +++ create_dynamic_sections, because they must be created +++ before the linker maps input sections to output +++ sections. The linker does that before +++ adjust_dynamic_symbol is called, and it is that +++ function which decides whether anything needs to go +++ into these sections. */ +++ s->flags |= SEC_EXCLUDE; +++ continue; +++ } +++ +++ if ((s->flags & SEC_HAS_CONTENTS) == 0) +++ continue; +++ +++ /* Allocate memory for the section contents. Zero the memory +++ for the benefit of .rela.plt, which has 4 unused entries +++ at the beginning, and we don't want garbage. */ +++ s->contents = (bfd_byte *) bfd_zalloc (dynobj, s->size); +++ if (s->contents == NULL) +++ return FALSE; +++ } +++ +++ if (elf_hash_table (info)->dynamic_sections_created) +++ { +++ /* Add some entries to the .dynamic section. We fill in the +++ values later, in loongarch_elf_finish_dynamic_sections, but we +++ must add the entries now so that we get the correct size for +++ the .dynamic section. The DT_DEBUG entry is filled in by the +++ dynamic linker and used by the debugger. */ +++#define add_dynamic_entry(TAG, VAL) \ +++ _bfd_elf_add_dynamic_entry (info, TAG, VAL) +++ +++ if (bfd_link_executable (info)) +++ { +++ if (!add_dynamic_entry (DT_DEBUG, 0)) +++ return FALSE; +++ } +++ +++ if (htab->elf.srelplt->size != 0) +++ { +++ if (!add_dynamic_entry (DT_PLTGOT, 0) +++ || !add_dynamic_entry (DT_PLTRELSZ, 0) +++ || !add_dynamic_entry (DT_PLTREL, DT_RELA) +++ || !add_dynamic_entry (DT_JMPREL, 0)) +++ return FALSE; +++ } +++ +++ if (!add_dynamic_entry (DT_RELA, 0) +++ || !add_dynamic_entry (DT_RELASZ, 0) +++ || !add_dynamic_entry (DT_RELAENT, sizeof (ElfNN_External_Rela))) +++ return FALSE; +++ +++ /* If any dynamic relocs apply to a read-only section, +++ then we need a DT_TEXTREL entry. */ +++ if ((info->flags & DF_TEXTREL) == 0) +++ elf_link_hash_traverse (&htab->elf, maybe_set_textrel, info); +++ +++ if (info->flags & DF_TEXTREL) +++ { +++ if (!add_dynamic_entry (DT_TEXTREL, 0)) +++ return FALSE; +++ /* Clear the DF_TEXTREL flag. It will be set again if we +++ write out an actual text relocation; we may not, because +++ at this point we do not know whether e.g. any .eh_frame +++ absolute relocations have been converted to PC-relative. */ +++ info->flags &= ~DF_TEXTREL; +++ } +++ } +++#undef add_dynamic_entry +++ +++ return TRUE; +++} +++ +++ +++#define LARCH_LD_STACK_DEPTH 16 +++static int64_t lisa_opc_stack[LARCH_LD_STACK_DEPTH]; +++static size_t lisa_stack_top = 0; +++ +++static bfd_reloc_status_type +++loongarch_push (int64_t val) +++{ +++ if (LARCH_LD_STACK_DEPTH <= lisa_stack_top) +++ return bfd_reloc_outofrange; +++ lisa_opc_stack[lisa_stack_top++] = val; +++ return bfd_reloc_ok; +++} +++ +++static bfd_reloc_status_type +++loongarch_pop (int64_t *val) +++{ +++ if (lisa_stack_top == 0) +++ return bfd_reloc_outofrange; +++ BFD_ASSERT (val); +++ *val = lisa_opc_stack[--lisa_stack_top]; +++ return bfd_reloc_ok; +++} +++ +++static bfd_reloc_status_type +++loongarch_top (int64_t *val) +++{ +++ if (lisa_stack_top == 0) +++ return bfd_reloc_outofrange; +++ BFD_ASSERT (val); +++ *val = lisa_opc_stack[lisa_stack_top - 1]; +++ return bfd_reloc_ok; +++} +++ +++static void +++loongarch_elf_append_rela (bfd *abfd, asection *s, Elf_Internal_Rela *rel) +++{ +++ const struct elf_backend_data *bed; +++ bfd_byte *loc; +++ +++ bed = get_elf_backend_data (abfd); +++ loc = s->contents + (s->reloc_count++ * bed->s->sizeof_rela); +++ bed->s->swap_reloca_out (abfd, rel, loc); +++} +++ +++/* Emplace a static relocation. */ +++ +++static bfd_reloc_status_type +++perform_relocation (const Elf_Internal_Rela *rel, +++ bfd_vma value, +++ bfd *input_bfd, +++ bfd_byte *contents) +++{ +++ +++ uint32_t insn1; +++ int64_t opr1, opr2, opr3; +++ bfd_reloc_status_type r = bfd_reloc_ok; +++ switch (ELFNN_R_TYPE (rel->r_info)) +++ { +++ case R_LARCH_SOP_PUSH_PCREL: +++ case R_LARCH_SOP_PUSH_ABSOLUTE: +++ case R_LARCH_SOP_PUSH_GPREL: +++ case R_LARCH_SOP_PUSH_TLS_TPREL: +++ case R_LARCH_SOP_PUSH_TLS_GOT: +++ case R_LARCH_SOP_PUSH_TLS_GD: +++ case R_LARCH_SOP_PUSH_PLT_PCREL: +++ r = loongarch_push (value); +++ break; +++ +++ case R_LARCH_SOP_PUSH_DUP: +++ r = bfd_reloc_outofrange; +++ if (loongarch_pop (&opr1) != bfd_reloc_ok +++ || loongarch_push (opr1) != bfd_reloc_ok +++ || loongarch_push (opr1) != bfd_reloc_ok) +++ break; +++ r = bfd_reloc_ok; +++ break; +++ +++ case R_LARCH_SOP_ASSERT: +++ r = loongarch_pop (&opr1); +++ if (r != bfd_reloc_ok && opr1 == FALSE) +++ r = bfd_reloc_notsupported; +++ break; +++ +++ case R_LARCH_SOP_NOT: +++ r = bfd_reloc_outofrange; +++ if (loongarch_pop (&opr1) != bfd_reloc_ok +++ || loongarch_push (!opr1) != bfd_reloc_ok) +++ break; +++ r = bfd_reloc_ok; +++ break; +++ +++ case R_LARCH_SOP_SUB: +++ r = bfd_reloc_outofrange; +++ if (loongarch_pop (&opr2) != bfd_reloc_ok +++ || loongarch_pop (&opr1) != bfd_reloc_ok +++ || loongarch_push (opr1 - opr2) != bfd_reloc_ok) +++ break; +++ r = bfd_reloc_ok; +++ break; +++ +++ case R_LARCH_SOP_SL: +++ r = bfd_reloc_outofrange; +++ if (loongarch_pop (&opr2) != bfd_reloc_ok +++ || loongarch_pop (&opr1) != bfd_reloc_ok +++ || loongarch_push (opr1 << opr2) != bfd_reloc_ok) +++ break; +++ r = bfd_reloc_ok; +++ break; +++ +++ case R_LARCH_SOP_SR: +++ r = bfd_reloc_outofrange; +++ if (loongarch_pop (&opr2) != bfd_reloc_ok +++ || loongarch_pop (&opr1) != bfd_reloc_ok +++ || loongarch_push (opr1 >> opr2) != bfd_reloc_ok) +++ break; +++ r = bfd_reloc_ok; +++ break; +++ +++ case R_LARCH_SOP_AND: +++ r = bfd_reloc_outofrange; +++ if (loongarch_pop (&opr2) != bfd_reloc_ok +++ || loongarch_pop (&opr1) != bfd_reloc_ok +++ || loongarch_push (opr1 & opr2) != bfd_reloc_ok) +++ break; +++ r = bfd_reloc_ok; +++ break; +++ +++ case R_LARCH_SOP_ADD: +++ r = bfd_reloc_outofrange; +++ if (loongarch_pop (&opr2) != bfd_reloc_ok +++ || loongarch_pop (&opr1) != bfd_reloc_ok +++ || loongarch_push (opr1 + opr2) != bfd_reloc_ok) +++ break; +++ r = bfd_reloc_ok; +++ break; +++ +++ case R_LARCH_SOP_IF_ELSE: +++ r = bfd_reloc_outofrange; +++ if (loongarch_pop (&opr3) != bfd_reloc_ok +++ || loongarch_pop (&opr2) != bfd_reloc_ok +++ || loongarch_pop (&opr1) != bfd_reloc_ok +++ || loongarch_push (opr1 ? opr2 : opr3) != bfd_reloc_ok) +++ break; +++ r = bfd_reloc_ok; +++ break; +++ +++ case R_LARCH_SOP_POP_32_S_10_5: +++ r = loongarch_pop (&opr1); +++ if (r != bfd_reloc_ok) +++ break; +++ if ((opr1 & ~(uint64_t)0xf) != 0x0 +++ && (opr1 & ~(uint64_t)0xf) != ~(uint64_t)0xf) +++ r = bfd_reloc_overflow; +++ if (r != bfd_reloc_ok) +++ break; +++ insn1 = bfd_get (32, input_bfd, contents + rel->r_offset); +++ insn1 = (insn1 & (~(uint32_t)0x7c00)) | ((opr1 & 0x1f) << 10); +++ bfd_put (32, input_bfd, insn1, contents + rel->r_offset); +++ break; +++ +++ case R_LARCH_SOP_POP_32_U_10_12: +++ r = loongarch_pop (&opr1); +++ if (r != bfd_reloc_ok) +++ break; +++ if (opr1 & ~(uint64_t)0xfff) +++ r = bfd_reloc_overflow; +++ if (r != bfd_reloc_ok) +++ break; +++ insn1 = bfd_get (32, input_bfd, contents + rel->r_offset); +++ insn1 = (insn1 & (~(uint32_t)0x3ffc00)) | ((opr1 & 0xfff) << 10); +++ bfd_put (32, input_bfd, insn1, contents + rel->r_offset); +++ break; +++ +++ case R_LARCH_SOP_POP_32_S_10_12: +++ r = loongarch_pop (&opr1); +++ if (r != bfd_reloc_ok) +++ break; +++ if ((opr1 & ~(uint64_t)0x7ff) != 0x0 +++ && (opr1 & ~(uint64_t)0x7ff) != ~(uint64_t)0x7ff) +++ r = bfd_reloc_overflow; +++ if (r != bfd_reloc_ok) +++ break; +++ insn1 = bfd_get (32, input_bfd, contents + rel->r_offset); +++ insn1 = (insn1 & (~(uint32_t)0x3ffc00)) | ((opr1 & 0xfff) << 10); +++ bfd_put (32, input_bfd, insn1, contents + rel->r_offset); +++ break; +++ +++ case R_LARCH_SOP_POP_32_S_10_16: +++ r = loongarch_pop (&opr1); +++ if (r != bfd_reloc_ok) +++ break; +++ if ((opr1 & ~(uint64_t)0x7fff) != 0x0 +++ && (opr1 & ~(uint64_t)0x7fff) != ~(uint64_t)0x7fff) +++ r = bfd_reloc_overflow; +++ if (r != bfd_reloc_ok) +++ break; +++ insn1 = bfd_get (32, input_bfd, contents + rel->r_offset); +++ insn1 = (insn1 & 0xfc0003ff) | ((opr1 & 0xffff) << 10); +++ bfd_put (32, input_bfd, insn1, contents + rel->r_offset); +++ break; +++ +++ case R_LARCH_SOP_POP_32_S_10_16_S2: +++ r = loongarch_pop (&opr1); +++ if (r != bfd_reloc_ok) +++ break; +++ if ((opr1 & 0x3) != 0) +++ r = bfd_reloc_overflow; +++ opr1 >>= 2; +++ if ((opr1 & ~(uint64_t)0x7fff) != 0x0 +++ && (opr1 & ~(uint64_t)0x7fff) != ~(uint64_t)0x7fff) +++ r = bfd_reloc_overflow; +++ if (r != bfd_reloc_ok) +++ break; +++ insn1 = bfd_get (32, input_bfd, contents + rel->r_offset); +++ insn1 = (insn1 & 0xfc0003ff) | ((opr1 & 0xffff) << 10); +++ bfd_put (32, input_bfd, insn1, contents + rel->r_offset); +++ break; +++ +++ case R_LARCH_SOP_POP_32_S_0_5_10_16_S2: +++ r = loongarch_pop (&opr1); +++ if (r != bfd_reloc_ok) +++ break; +++ if ((opr1 & 0x3) != 0) +++ r = bfd_reloc_overflow; +++ opr1 >>= 2; +++ if ((opr1 & ~(uint64_t)0xfffff) != 0x0 +++ && (opr1 & ~(uint64_t)0xfffff) != ~(uint64_t)0xfffff) +++ r = bfd_reloc_overflow; +++ if (r != bfd_reloc_ok) +++ break; +++ insn1 = bfd_get (32, input_bfd, contents + rel->r_offset); +++ insn1 = (insn1 & 0xfc0003e0) +++ | ((opr1 & 0xffff) << 10) | ((opr1 & 0x1f0000) >> 16); +++ bfd_put (32, input_bfd, insn1, contents + rel->r_offset); +++ break; +++ +++ case R_LARCH_SOP_POP_32_S_5_20: +++ r = loongarch_pop (&opr1); +++ if (r != bfd_reloc_ok) +++ break; +++ if ((opr1 & ~(uint64_t)0x7ffff) != 0x0 +++ && (opr1 & ~(uint64_t)0x7ffff) != ~(uint64_t)0x7ffff) +++ r = bfd_reloc_overflow; +++ if (r != bfd_reloc_ok) +++ break; +++ insn1 = bfd_get (32, input_bfd, contents + rel->r_offset); +++ insn1 = (insn1 & (~(uint32_t)0x1ffffe0)) | ((opr1 & 0xfffff) << 5); +++ bfd_put (32, input_bfd, insn1, contents + rel->r_offset); +++ break; +++ +++ case R_LARCH_SOP_POP_32_S_0_10_10_16_S2: +++ r = loongarch_pop (&opr1); +++ if (r != bfd_reloc_ok) +++ break; +++ if ((opr1 & 0x3) != 0) +++ r = bfd_reloc_overflow; +++ opr1 >>= 2; +++ if ((opr1 & ~(uint64_t)0x1ffffff) != 0x0 +++ && (opr1 & ~(uint64_t)0x1ffffff) != ~(uint64_t)0x1ffffff) +++ r = bfd_reloc_overflow; +++ if (r != bfd_reloc_ok) +++ break; +++ insn1 = bfd_get (32, input_bfd, contents + rel->r_offset); +++ insn1 = (insn1 & 0xfc000000) +++ | ((opr1 & 0xffff) << 10) | ((opr1 & 0x3ff0000) >> 16); +++ bfd_put (32, input_bfd, insn1, contents + rel->r_offset); +++ break; +++ +++ case R_LARCH_SOP_POP_32_U: +++ r = loongarch_pop (&opr1); +++ if (r != bfd_reloc_ok) +++ break; +++ if (opr1 & ~(uint64_t)0xffffffff) +++ r = bfd_reloc_overflow; +++ if (r != bfd_reloc_ok) +++ break; +++ bfd_put (32, input_bfd, opr1, contents + rel->r_offset); +++ break; +++ +++ case R_LARCH_TLS_DTPREL32: +++ case R_LARCH_32: +++ bfd_put (32, input_bfd, value, contents + rel->r_offset); +++ break; +++ case R_LARCH_TLS_DTPREL64: +++ case R_LARCH_64: +++ bfd_put (64, input_bfd, value, contents + rel->r_offset); +++ break; +++ case R_LARCH_ADD8: +++ opr1 = bfd_get (8, input_bfd, contents + rel->r_offset); +++ bfd_put (8, input_bfd, opr1 + value, contents + rel->r_offset); +++ break; +++ case R_LARCH_ADD16: +++ opr1 = bfd_get (16, input_bfd, contents + rel->r_offset); +++ bfd_put (16, input_bfd, opr1 + value, contents + rel->r_offset); +++ break; +++ case R_LARCH_ADD24: +++ opr1 = bfd_get (24, input_bfd, contents + rel->r_offset); +++ bfd_put (24, input_bfd, opr1 + value, contents + rel->r_offset); +++ break; +++ case R_LARCH_ADD32: +++ opr1 = bfd_get (32, input_bfd, contents + rel->r_offset); +++ bfd_put (32, input_bfd, opr1 + value, contents + rel->r_offset); +++ break; +++ case R_LARCH_ADD64: +++ opr1 = bfd_get (64, input_bfd, contents + rel->r_offset); +++ bfd_put (64, input_bfd, opr1 + value, contents + rel->r_offset); +++ break; +++ case R_LARCH_SUB8: +++ opr1 = bfd_get (8, input_bfd, contents + rel->r_offset); +++ bfd_put (8, input_bfd, opr1 - value, contents + rel->r_offset); +++ break; +++ case R_LARCH_SUB16: +++ opr1 = bfd_get (16, input_bfd, contents + rel->r_offset); +++ bfd_put (16, input_bfd, opr1 - value, contents + rel->r_offset); +++ break; +++ case R_LARCH_SUB24: +++ opr1 = bfd_get (24, input_bfd, contents + rel->r_offset); +++ bfd_put (24, input_bfd, opr1 - value, contents + rel->r_offset); +++ break; +++ case R_LARCH_SUB32: +++ opr1 = bfd_get (32, input_bfd, contents + rel->r_offset); +++ bfd_put (32, input_bfd, opr1 - value, contents + rel->r_offset); +++ break; +++ case R_LARCH_SUB64: +++ opr1 = bfd_get (64, input_bfd, contents + rel->r_offset); +++ bfd_put (64, input_bfd, opr1 - value, contents + rel->r_offset); +++ break; +++ +++ default: +++ r = bfd_reloc_notsupported; +++ } +++ return r; +++} +++ +++ +++#define LARCH_RECENT_RELOC_QUEUE_LENGTH 72 +++static struct +++{ +++ bfd *bfd; +++ asection *section; +++ bfd_vma r_offset; +++ int r_type; +++ bfd_vma relocation; +++ Elf_Internal_Sym *sym; +++ struct elf_link_hash_entry *h; +++ bfd_vma addend; +++ int64_t top_then; +++} lisa_reloc_queue [LARCH_RECENT_RELOC_QUEUE_LENGTH]; +++static size_t lisa_reloc_queue_head = 0; +++static size_t lisa_reloc_queue_tail = 0; +++ +++static const char * +++loongarch_sym_name (bfd *input_bfd, struct elf_link_hash_entry *h, +++ Elf_Internal_Sym *sym) +++{ +++ const char *ret = NULL; +++ if (sym) +++ ret = bfd_elf_string_from_elf_section +++ (input_bfd, elf_symtab_hdr (input_bfd).sh_link, sym->st_name); +++ else if (h) +++ ret = h->root.root.string; +++ +++ if (ret == NULL || *ret == '\0') +++ ret = ""; +++ return ret; +++} +++ +++static void +++loongarch_record_one_reloc (bfd *abfd, asection *section, int r_type, +++ bfd_vma r_offset, Elf_Internal_Sym *sym, +++ struct elf_link_hash_entry *h, bfd_vma addend) +++{ +++ if ((lisa_reloc_queue_head == 0 +++ && lisa_reloc_queue_tail == LARCH_RECENT_RELOC_QUEUE_LENGTH - 1) +++ || (lisa_reloc_queue_head == lisa_reloc_queue_tail + 1)) +++ lisa_reloc_queue_head = +++ (lisa_reloc_queue_head + 1) % LARCH_RECENT_RELOC_QUEUE_LENGTH; +++ lisa_reloc_queue[lisa_reloc_queue_tail].bfd = abfd; +++ lisa_reloc_queue[lisa_reloc_queue_tail].section = section; +++ lisa_reloc_queue[lisa_reloc_queue_tail].r_offset = r_offset; +++ lisa_reloc_queue[lisa_reloc_queue_tail].r_type = r_type; +++ lisa_reloc_queue[lisa_reloc_queue_tail].sym = sym; +++ lisa_reloc_queue[lisa_reloc_queue_tail].h = h; +++ lisa_reloc_queue[lisa_reloc_queue_tail].addend = addend; +++ loongarch_top (&lisa_reloc_queue[lisa_reloc_queue_tail].top_then); +++ lisa_reloc_queue_tail = +++ (lisa_reloc_queue_tail + 1) % LARCH_RECENT_RELOC_QUEUE_LENGTH; +++} +++ +++static void +++loongarch_dump_reloc_record (void (*p) (const char *fmt, ...)) +++{ +++ size_t i = lisa_reloc_queue_head; +++ bfd *a_bfd = NULL; +++ asection *section = NULL; +++ bfd_vma r_offset = 0; +++ int inited = 0; +++ p ("Dump relocate record:\n"); +++ p ("stack top\t\trelocation name\t\tsymbol"); +++ while (i != lisa_reloc_queue_tail) +++ { +++ if (a_bfd != lisa_reloc_queue[i].bfd +++ || section != lisa_reloc_queue[i].section +++ || r_offset != lisa_reloc_queue[i].r_offset) +++ { +++ a_bfd = lisa_reloc_queue[i].bfd; +++ section = lisa_reloc_queue[i].section; +++ r_offset = lisa_reloc_queue[i].r_offset; +++ p ("\nat %pB(%pA+0x%v):\n", +++ lisa_reloc_queue[i].bfd, +++ lisa_reloc_queue[i].section, +++ lisa_reloc_queue[i].r_offset); +++ } +++ +++ if (!inited) +++ inited = 1, p ("...\n"); +++ +++ reloc_howto_type *howto = +++ loongarch_elf_rtype_to_howto (lisa_reloc_queue[i].r_type); +++ p ("0x%V %s\t`%s'", +++ (bfd_vma) lisa_reloc_queue[i].top_then, +++ howto ? howto->name : "", +++ loongarch_sym_name (lisa_reloc_queue[i].bfd, +++ lisa_reloc_queue[i].h, +++ lisa_reloc_queue[i].sym)); +++ +++ long addend = lisa_reloc_queue[i].addend; +++ if (addend < 0) +++ p (" - %ld", -addend); +++ else if (0 < addend) +++ p (" + %ld(0x%v)", addend, lisa_reloc_queue[i].addend); +++ +++ p ("\n"); +++ i = (i + 1) % LARCH_RECENT_RELOC_QUEUE_LENGTH; +++ } +++ p ("\n" "-- Record dump end --\n\n"); +++} +++ +++ +++static bfd_boolean +++loongarch_elf_relocate_section (bfd *output_bfd, +++ struct bfd_link_info *info, +++ bfd *input_bfd, +++ asection *input_section, +++ bfd_byte *contents, +++ Elf_Internal_Rela *relocs, +++ Elf_Internal_Sym *local_syms, +++ asection **local_sections) +++{ +++ Elf_Internal_Rela *rel; +++ Elf_Internal_Rela *relend; +++ bfd_boolean fatal = FALSE; +++ asection *sreloc = elf_section_data (input_section)->sreloc; +++ struct loongarch_elf_link_hash_table *htab = loongarch_elf_hash_table (info); +++ Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (input_bfd); +++ struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (input_bfd); +++ bfd_vma *local_got_offsets = elf_local_got_offsets (input_bfd); +++ bfd_boolean is_pic = bfd_link_pic (info); +++ bfd_boolean is_dyn = elf_hash_table (info)->dynamic_sections_created; +++ asection *plt = htab->elf.splt ? htab->elf.splt : htab->elf.iplt; +++ asection *got = htab->elf.sgot; +++ +++ relend = relocs + input_section->reloc_count; +++ for (rel = relocs; rel < relend; rel++) +++ { +++ int r_type = ELFNN_R_TYPE (rel->r_info); +++ unsigned long r_symndx = ELFNN_R_SYM (rel->r_info); +++ bfd_vma pc = sec_addr (input_section) + rel->r_offset; +++ reloc_howto_type *howto = loongarch_elf_rtype_to_howto (r_type); +++ asection *sec = NULL; +++ Elf_Internal_Sym *sym = NULL; +++ struct elf_link_hash_entry *h = NULL; +++ const char *name; +++ bfd_reloc_status_type r = bfd_reloc_ok; +++ bfd_boolean is_ie, is_undefweak, unresolved_reloc, defined_local; +++ bfd_boolean resolved_local, resolved_dynly, resolved_to_const; +++ char tls_type; +++ bfd_vma relocation; +++ bfd_vma off, ie_off; +++ int i, j; +++ +++ if (howto == NULL +++ || r_type == R_LARCH_GNU_VTINHERIT +++ || r_type == R_LARCH_GNU_VTENTRY) +++ continue; +++ +++ /* This is a final link. */ +++ if (r_symndx < symtab_hdr->sh_info) +++ { +++ is_undefweak = FALSE; +++ unresolved_reloc = FALSE; +++ sym = local_syms + r_symndx; +++ sec = local_sections[r_symndx]; +++ relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); +++ +++ /* Relocate against local STT_GNU_IFUNC symbol. */ +++ if (!bfd_link_relocatable (info) +++ && ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC) +++ { +++ h = elfNN_loongarch_get_local_sym_hash +++ (htab, input_bfd, rel, FALSE); +++ if (h == NULL) +++ abort (); +++ +++ /* Set STT_GNU_IFUNC symbol value. */ +++ h->root.u.def.value = sym->st_value; +++ h->root.u.def.section = sec; +++ } +++ defined_local = TRUE; +++ resolved_local = TRUE; +++ resolved_dynly = FALSE; +++ resolved_to_const = FALSE; +++ if (bfd_link_relocatable(info) +++ && ELF_ST_TYPE(sym->st_info) == STT_SECTION) { +++ rel->r_addend += sec->output_offset; +++ } +++ } +++ else +++ { +++ bfd_boolean warned, ignored; +++ +++ RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, +++ r_symndx, symtab_hdr, sym_hashes, +++ h, sec, relocation, +++ unresolved_reloc, warned, ignored); +++ /* here means symbol isn't local symbol only and 'h != NULL' */ +++ +++ /* 'unresolved_syms_in_objects' specify how to deal with undefined +++ symbol. And 'dynamic_undefined_weak' specify what to do when +++ meeting undefweak. */ +++ +++ if ((is_undefweak = h->root.type == bfd_link_hash_undefweak)) +++ { +++ defined_local = FALSE; +++ resolved_local = FALSE; +++ resolved_to_const = !is_dyn || h->dynindx == -1 +++ || UNDEFWEAK_NO_DYNAMIC_RELOC (info, h); +++ resolved_dynly = !resolved_local && !resolved_to_const; +++ } +++ else if (warned) +++ { +++ /* Symbol undefined offen means failed already. I don't know why +++ 'warned' here but I guess it want to continue relocating as if +++ no error occures to find other errors as more as possible. */ +++ +++ /* To avoid generating warning messages about truncated +++ relocations, set the relocation's address to be the same as +++ the start of this section. */ +++ relocation = input_section->output_section +++ ? input_section->output_section->vma : 0; +++ +++ defined_local = relocation != 0; +++ resolved_local = defined_local; +++ resolved_to_const = !resolved_local; +++ resolved_dynly = FALSE; +++ } +++ else +++ { +++ defined_local = !unresolved_reloc && !ignored; +++ resolved_local = +++ defined_local && SYMBOL_REFERENCES_LOCAL (info, h); +++ resolved_dynly = !resolved_local; +++ resolved_to_const = !resolved_local && !resolved_dynly; +++ } +++ } +++ +++ name = loongarch_sym_name (input_bfd, h, sym); +++ +++ if (sec != NULL && discarded_section (sec)) +++ RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, +++ rel, 1, relend, howto, 0, contents); +++ +++ if (bfd_link_relocatable (info)) +++ continue; +++ +++ /* r_symndx will be STN_UNDEF (zero) only for relocs against symbols +++ from removed linkonce sections, or sections discarded by a linker +++ script. Also for R_*_SOP_PUSH_ABSOLUTE and PCREL to specify const. */ +++ if (r_symndx == STN_UNDEF || bfd_is_abs_section (sec)) +++ resolved_dynly = resolved_local = defined_local = FALSE +++ , resolved_to_const = TRUE; +++ +++ if (h && h->type == STT_GNU_IFUNC) +++ { +++ /* a. 动态连接器可以直接处理STT_GNU_IFUNC,因为动态连接器可以察觉到 +++ 一个动态符号是STT_GNU_IFUNC,从而在装载时执行resolver; +++ 但local符号不行,因为根本没有动态符号,所以要将R_LARCH_64转化为 +++ R_LARCH_IRELATIVE,类似的,所有其他重定位类型可能都要针对IFUNC +++ 做一些特殊操作,我觉得有点麻烦了。 +++ b. 此外,比如代码段的重定位无法动态改变其的引用位置,所以必须走plt +++ 来实现IFUNC。 +++ c. 因此,为方便实现,我们将plt stub的位置当作IFUNC符号的定义。 */ +++ if (h->plt.offset == MINUS_ONE) +++ info->callbacks->info +++ ("%X%pB(%pA+0x%v): error: %s against `%s':\n" +++ "STT_GNU_IFUNC must have PLT stub" "\n", +++ input_bfd, input_section, (bfd_vma) rel->r_offset, +++ howto->name, name); +++ defined_local = TRUE; +++ resolved_local = TRUE; +++ resolved_dynly = FALSE; +++ resolved_to_const = FALSE; +++ relocation = sec_addr (plt) + h->plt.offset; +++ } +++ +++ unresolved_reloc = resolved_dynly; +++ +++ BFD_ASSERT (resolved_local + resolved_dynly + resolved_to_const == 1); +++ +++ /* a. 命题 'resolved_dynly' ==> 'h && h->dynindx != -1' 成立。 +++ b. 需要动态重定位一个符号当然需要动态符号表。这个断言失败意味着某个 +++ 动态符号没有执行bfd_elf_link_record_dynamic_symbol。之前的逻辑有问题 +++ c. 另外,即使resolved_dynly为真,也不一定真的生成动态重定位表项,因为 +++ 有时section没有SEC_ALLOC这个flag,当段不需要被加载进内存自然不需要动态 +++ 重定位。 */ +++ BFD_ASSERT (!resolved_dynly || (h && h->dynindx != -1)); +++ +++ BFD_ASSERT (!resolved_local || defined_local); +++ +++ is_ie = FALSE; +++ switch (r_type) +++ { +++#define LARCH_ASSERT(cond, bfd_fail_state, message) \ +++ ({if (!(cond)) { \ +++ r = bfd_fail_state; \ +++ switch (r) { \ +++ /* 'dangerous' means we do it but can't promise it's ok \ +++ 'unsupport' means out of ability of relocation type \ +++ 'undefined' means we can't deal with the undefined symbol */ \ +++ case bfd_reloc_undefined: \ +++ info->callbacks->undefined_symbol \ +++ (info, name, input_bfd, input_section, rel->r_offset, TRUE); \ +++ default: \ +++ fatal = TRUE; \ +++ info->callbacks->info \ +++ ("%X%pB(%pA+0x%v): error: %s against %s`%s':\n" \ +++ message "\n", \ +++ input_bfd, input_section, (bfd_vma) rel->r_offset, \ +++ howto->name, is_undefweak? "[undefweak] " : "", name); \ +++ break; \ +++ case bfd_reloc_dangerous: \ +++ info->callbacks->info \ +++ ("%pB(%pA+0x%v): warning: %s against %s`%s':\n" \ +++ message "\n", \ +++ input_bfd, input_section, (bfd_vma) rel->r_offset, \ +++ howto->name, is_undefweak? "[undefweak] " : "", name); \ +++ break; \ +++ case bfd_reloc_ok: \ +++ case bfd_reloc_continue: \ +++ info->callbacks->info \ +++ ("%pB(%pA+0x%v): message: %s against %s`%s':\n" \ +++ message "\n", \ +++ input_bfd, input_section, (bfd_vma) rel->r_offset, \ +++ howto->name, is_undefweak? "[undefweak] " : "", name); \ +++ break; \ +++ } \ +++ if (fatal) break; \ +++ }}) +++ case R_LARCH_MARK_PCREL: +++ case R_LARCH_MARK_LA: +++ case R_LARCH_NONE: +++ r = bfd_reloc_continue; +++ unresolved_reloc = FALSE; +++ break; +++ +++ case R_LARCH_32: +++ case R_LARCH_64: +++ if (resolved_dynly || (is_pic && resolved_local)) +++ { +++ Elf_Internal_Rela outrel; +++ +++ /* When generating a shared object, these relocations are copied +++ into the output file to be resolved at run time. */ +++ +++ outrel.r_offset = +++ _bfd_elf_section_offset (output_bfd, info, input_section, +++ rel->r_offset); +++ +++ unresolved_reloc = !((bfd_vma) -2 <= outrel.r_offset) +++ && (input_section->flags & SEC_ALLOC); +++ +++ outrel.r_offset += sec_addr (input_section); +++ if (resolved_dynly) +++ { +++ outrel.r_info = ELFNN_R_INFO (h->dynindx, r_type); +++ outrel.r_addend = rel->r_addend; +++ } +++ else +++ { +++ outrel.r_info = ELFNN_R_INFO (0, R_LARCH_RELATIVE); +++ outrel.r_addend = relocation + rel->r_addend; +++ } +++ +++ if (unresolved_reloc) +++ loongarch_elf_append_rela (output_bfd, sreloc, &outrel); +++ } +++ +++ relocation += rel->r_addend; +++ break; +++ +++ case R_LARCH_ADD8: +++ case R_LARCH_ADD16: +++ case R_LARCH_ADD24: +++ case R_LARCH_ADD32: +++ case R_LARCH_ADD64: +++ case R_LARCH_SUB8: +++ case R_LARCH_SUB16: +++ case R_LARCH_SUB24: +++ case R_LARCH_SUB32: +++ case R_LARCH_SUB64: +++ LARCH_ASSERT (!resolved_dynly, bfd_reloc_undefined, +++"Can't be resolved dynamically. If this procedure is hand-writing assemble,\n" +++"there must be something like '.dword sym1 - sym2' to generate these relocs\n" +++"and we can't get known link-time address of these symbols."); +++ relocation += rel->r_addend; +++ break; +++ +++ case R_LARCH_TLS_DTPREL32: +++ case R_LARCH_TLS_DTPREL64: +++ if (resolved_dynly) +++ { +++ Elf_Internal_Rela outrel; +++ +++ outrel.r_offset = +++ _bfd_elf_section_offset (output_bfd, info, input_section, +++ rel->r_offset); +++ +++ unresolved_reloc = !((bfd_vma) -2 <= outrel.r_offset) +++ && (input_section->flags & SEC_ALLOC); +++ outrel.r_info = ELFNN_R_INFO (h->dynindx, r_type); +++ outrel.r_offset += sec_addr (input_section); +++ outrel.r_addend = rel->r_addend; +++ if (unresolved_reloc) +++ loongarch_elf_append_rela (output_bfd, sreloc, &outrel); +++ break; +++ } +++ +++ LARCH_ASSERT (!resolved_to_const, bfd_reloc_notsupported, +++ "Internal:"); +++ +++ case R_LARCH_SOP_PUSH_TLS_TPREL: +++ if (resolved_local) +++ { +++ LARCH_ASSERT (elf_hash_table (info)->tls_sec, +++ bfd_reloc_notsupported, "TLS section not be created"); +++ relocation -= elf_hash_table (info)->tls_sec->vma; +++ } +++ +++ LARCH_ASSERT (resolved_local, bfd_reloc_undefined, +++ "TLS LE just can be resolved local only."); +++ break; +++ +++ case R_LARCH_SOP_PUSH_ABSOLUTE: +++ if (is_undefweak) +++ { +++ LARCH_ASSERT (!resolved_dynly, bfd_reloc_dangerous, +++"Someone require us to resolve undefweak symbol dynamically.\n" +++"But this reloc can't be done. I think I can't throw error for this\n" +++"so I resolved it to 0. I suggest to re-compile with '-fpic'."); +++ relocation = 0; +++ unresolved_reloc = FALSE; +++ break; +++ } +++ +++ if (resolved_to_const) +++ { +++ relocation += rel->r_addend; +++ break; +++ } +++ +++ LARCH_ASSERT (!is_pic, bfd_reloc_notsupported, +++"Under PIC we don't know load address. Re-compile src with '-fpic'?"); +++ +++ if (resolved_dynly) +++ { +++ LARCH_ASSERT (plt && h && h->plt.offset != MINUS_ONE, +++ bfd_reloc_undefined, +++"Can't be resolved dynamically. Try to re-compile src with '-fpic'?"); +++ +++ LARCH_ASSERT (rel->r_addend == 0, bfd_reloc_notsupported, +++ "Shouldn't be with r_addend."); +++ +++ relocation = sec_addr (plt) + h->plt.offset; +++ unresolved_reloc = FALSE; +++ break; +++ } +++ +++ if (resolved_local) +++ { +++ relocation += rel->r_addend; +++ break; +++ } +++ +++ break; +++ +++ case R_LARCH_SOP_PUSH_PCREL: +++ case R_LARCH_SOP_PUSH_PLT_PCREL: +++ unresolved_reloc = FALSE; +++ +++ if (resolved_to_const) +++ { +++ relocation += rel->r_addend; +++ break; +++ } +++ else if (is_undefweak) +++ { +++ i = 0, j = 0; +++ relocation = 0; +++ if (resolved_dynly) +++ { +++ if (h && h->plt.offset != MINUS_ONE) +++ i = 1, j = 2; +++ else +++ LARCH_ASSERT (0, bfd_reloc_dangerous, +++"Undefweak need to be resolved dynamically, but PLT stub doesn't represent."); +++ } +++ } +++ else +++ { +++ LARCH_ASSERT +++ (defined_local || (h && h->plt.offset != MINUS_ONE), +++ bfd_reloc_undefined, +++ "PLT stub does not represent and symbol not defined."); +++ +++ if (resolved_local) +++ i = 0, j = 2; +++ else /* if (resolved_dynly) */ +++ { +++ LARCH_ASSERT +++ (h && h->plt.offset != MINUS_ONE, bfd_reloc_dangerous, +++"Internal: PLT stub doesn't represent. Resolve it with pcrel"); +++ i = 1, j = 3; +++ } +++ } +++ +++ for (; i < j; i++) +++ { +++ if ((i & 1) == 0 && defined_local) +++ { +++ relocation -= pc; +++ relocation += rel->r_addend; +++ break; +++ } +++ +++ if ((i & 1) && h && h->plt.offset != MINUS_ONE) +++ { +++ LARCH_ASSERT (rel->r_addend == 0, bfd_reloc_notsupported, +++ "PLT shouldn't be with r_addend."); +++ relocation = sec_addr (plt) + h->plt.offset - pc; +++ break; +++ } +++ } +++ break; +++ +++ case R_LARCH_SOP_PUSH_GPREL: +++ unresolved_reloc = FALSE; +++ +++ LARCH_ASSERT (rel->r_addend == 0, bfd_reloc_notsupported, +++ "Shouldn't be with r_addend."); +++ +++ /* 约定在GOT表中写入连接时地址。动态连接器通过_GLOBAL_OFFSET_TABLE_的 +++ 连接时地址和运行时地址拿到模块的加载地址,拿到连接时地址的办法就是 +++ 拿到那个got entry。一些体系结构通过.dynamic的段基址拿到模块加载 +++ 地址,我没有这么做,因为这个段在static-pie下不存在。 */ +++ +++ if (h != NULL) +++ { +++ off = h->got.offset; +++ +++ LARCH_ASSERT (off != MINUS_ONE, bfd_reloc_notsupported, +++ "Internal: GOT entry doesn't represent."); +++ +++ if (!WILL_CALL_FINISH_DYNAMIC_SYMBOL (is_dyn, is_pic, h) +++ || (is_pic && SYMBOL_REFERENCES_LOCAL (info, h))) +++ { +++ /* This is actually a static link, or it is a +++ -Bsymbolic link and the symbol is defined +++ locally, or the symbol was forced to be local +++ because of a version file. We must initialize +++ this entry in the global offset table. Since the +++ offset must always be a multiple of the word size, +++ we use the least significant bit to record whether +++ we have initialized it already. +++ +++ When doing a dynamic link, we create a .rela.got +++ relocation entry to initialize the value. This +++ is done in the finish_dynamic_symbol routine. */ +++ +++ /* 在这里先不用管STT_GNU_IFUNC。elf_finish_dynamic_symbol +++ 会单独处理。 */ +++ +++ LARCH_ASSERT (!resolved_dynly, bfd_reloc_dangerous, +++ "Internal: here shouldn't dynamic."); +++ LARCH_ASSERT (defined_local || resolved_to_const, +++ bfd_reloc_undefined, "Internal: "); +++ +++ if ((off & 1) != 0) +++ off &= ~1; +++ else +++ { +++ bfd_put_NN (output_bfd, relocation, got->contents + off); +++ h->got.offset |= 1; +++ } +++ } +++ } +++ else +++ { +++ LARCH_ASSERT (local_got_offsets, bfd_reloc_notsupported, +++ "Internal: local got offsets not reporesent."); +++ +++ off = local_got_offsets[r_symndx]; +++ +++ LARCH_ASSERT (off != MINUS_ONE, bfd_reloc_notsupported, +++ "Internal: GOT entry doesn't represent."); +++ +++ /* The offset must always be a multiple of the word size. +++ So, we can use the least significant bit to record +++ whether we have already processed this entry. */ +++ if ((off & 1) != 0) +++ off &= ~1; +++ else +++ { +++ if (is_pic) +++ { +++ asection *s; +++ Elf_Internal_Rela outrel; +++ /* We need to generate a R_LARCH_RELATIVE reloc +++ for the dynamic linker. */ +++ s = htab->elf.srelgot; +++ LARCH_ASSERT (s, bfd_reloc_notsupported, +++ "Internal: '.rel.got' not represent"); +++ +++ outrel.r_offset = sec_addr (got) + off; +++ outrel.r_info = ELFNN_R_INFO (0, R_LARCH_RELATIVE); +++ outrel.r_addend = relocation; /* link-time addr */ +++ loongarch_elf_append_rela (output_bfd, s, &outrel); +++ } +++ +++ bfd_put_NN (output_bfd, relocation, got->contents + off); +++ local_got_offsets[r_symndx] |= 1; +++ } +++ } +++ relocation = off; +++ break; +++ +++ case R_LARCH_SOP_PUSH_TLS_GOT: +++ is_ie = TRUE; +++ case R_LARCH_SOP_PUSH_TLS_GD: +++ unresolved_reloc = FALSE; +++ +++ LARCH_ASSERT (rel->r_addend == 0, bfd_reloc_notsupported, +++ "Shouldn't be with r_addend."); +++ +++ if (resolved_to_const && is_undefweak && h->dynindx != -1) +++ { +++ /* What if undefweak? Let rtld make a decision. */ +++ resolved_to_const = resolved_local = FALSE; +++ resolved_dynly = TRUE; +++ } +++ +++ LARCH_ASSERT (!resolved_to_const, bfd_reloc_notsupported, +++ "Internal: Shouldn't be resolved to const."); +++ +++ if (h != NULL) +++ { +++ off = h->got.offset; +++ h->got.offset |= 1; +++ } +++ else +++ { +++ off = local_got_offsets[r_symndx]; +++ local_got_offsets[r_symndx] |= 1; +++ } +++ +++ LARCH_ASSERT (off != MINUS_ONE, bfd_reloc_notsupported, +++ "Internal: TLS GOT entry doesn't represent."); +++ +++ tls_type = _bfd_loongarch_elf_tls_type (input_bfd, h, r_symndx); +++ +++ /* If this symbol is referenced by both GD and IE TLS, the IE +++ reference's GOT slot follows the GD reference's slots. */ +++ ie_off = 0; +++ if ((tls_type & GOT_TLS_GD) && (tls_type & GOT_TLS_IE)) +++ ie_off = 2 * GOT_ENTRY_SIZE; +++ +++ if ((off & 1) != 0) +++ off &= ~1; +++ else +++ { +++ bfd_vma tls_block_off = 0; +++ Elf_Internal_Rela outrel; +++ +++ if (resolved_local) +++ { +++ LARCH_ASSERT +++ (elf_hash_table (info)->tls_sec, bfd_reloc_notsupported, +++ "Internal: TLS sec not represent."); +++ tls_block_off = relocation +++ - elf_hash_table (info)->tls_sec->vma; +++ } +++ +++ if (tls_type & GOT_TLS_GD) +++ { +++ outrel.r_offset = sec_addr (got) + off; +++ outrel.r_addend = 0; +++ bfd_put_NN (output_bfd, 0, got->contents + off); +++ if (resolved_local && bfd_link_executable (info)) +++ /* a. 第一个被装载模块的Module ID为1。$glibc/elf/rtld.c中 +++ 的dl_main有一句'main_map->l_tls_modid = 1'; +++ b. 静态程序的Module ID不重要,但为了省事仍然是1。 +++ 详见$glibc/csu/libc-tls.c中的init_static_tls。 */ +++ bfd_put_NN (output_bfd, 1, got->contents + off); +++ else if (resolved_local/* && !bfd_link_executable (info) */) +++ { +++ outrel.r_info = ELFNN_R_INFO (0, R_LARCH_TLS_DTPMODNN); +++ loongarch_elf_append_rela +++ (output_bfd, htab->elf.srelgot, &outrel); +++ } +++ else /* if (resolved_dynly) */ +++ { +++ outrel.r_info = +++ ELFNN_R_INFO (h->dynindx, R_LARCH_TLS_DTPMODNN); +++ loongarch_elf_append_rela +++ (output_bfd, htab->elf.srelgot, &outrel); +++ } +++ +++ outrel.r_offset += GOT_ENTRY_SIZE; +++ bfd_put_NN (output_bfd, tls_block_off, +++ got->contents + off + GOT_ENTRY_SIZE); +++ if (resolved_local) +++ /* DTPREL known */; +++ else /* if (resolved_dynly) */ +++ { +++ outrel.r_info = +++ ELFNN_R_INFO (h->dynindx, R_LARCH_TLS_DTPRELNN); +++ loongarch_elf_append_rela +++ (output_bfd, htab->elf.srelgot, &outrel); +++ } +++ } +++ +++ if (tls_type & GOT_TLS_IE) +++ { +++ outrel.r_offset = sec_addr (got) + off + ie_off; +++ bfd_put_NN (output_bfd, tls_block_off, +++ got->contents + off + ie_off); +++ if (resolved_local && bfd_link_executable (info)) +++ /* TPREL known */; +++ else if (resolved_local/* && !bfd_link_executable (info) */) +++ { +++ outrel.r_info = ELFNN_R_INFO (0, R_LARCH_TLS_TPRELNN); +++ outrel.r_addend = tls_block_off; +++ loongarch_elf_append_rela +++ (output_bfd, htab->elf.srelgot, &outrel); +++ } +++ else /* if (resolved_dynly) */ +++ { +++ outrel.r_info = +++ ELFNN_R_INFO (h->dynindx, R_LARCH_TLS_TPRELNN); +++ outrel.r_addend = 0; +++ loongarch_elf_append_rela +++ (output_bfd, htab->elf.srelgot, &outrel); +++ } +++ } +++ } +++ +++ relocation = off + (is_ie ? ie_off : 0); +++ break; +++ +++ default: +++ break; +++ } +++ +++ if (fatal) +++ break; +++ +++ do +++ { +++ /* 'unresolved_reloc' means we haven't done it yet. +++ We need help of dynamic linker to fix this memory location up. */ +++ if (!unresolved_reloc) +++ break; +++ +++ if (_bfd_elf_section_offset (output_bfd, info, input_section, +++ rel->r_offset) == MINUS_ONE) +++ /* WHY? May because it's invalid so skip checking. +++ But why dynamic reloc a invalid section? */ +++ break; +++ +++ if (input_section->output_section->flags & SEC_DEBUGGING) +++ { +++ LARCH_ASSERT (0, bfd_reloc_dangerous, +++ "Seems dynamic linker not process sections 'SEC_DEBUGGING'."); +++ break; +++ } +++ if (!is_dyn) +++ break; +++ +++ if ((info->flags & DF_TEXTREL) == 0) +++ if (input_section->output_section->flags & SEC_READONLY) +++ info->flags |= DF_TEXTREL; +++ } +++ while (0); +++#undef LARCH_ASSERT +++ +++ if (fatal) +++ break; +++ +++ loongarch_record_one_reloc (input_bfd, input_section, r_type, +++ rel->r_offset, sym, h, rel->r_addend); +++ +++ if (r != bfd_reloc_continue) +++ r = perform_relocation (rel, relocation, input_bfd, contents); +++ +++ switch (r) +++ { +++ case bfd_reloc_dangerous: +++ case bfd_reloc_continue: +++ case bfd_reloc_ok: +++ continue; +++ +++ case bfd_reloc_overflow: +++ /* Overflow value can't be filled in */ +++ loongarch_dump_reloc_record (info->callbacks->info); +++ info->callbacks->reloc_overflow +++ (info, (h ? &h->root : NULL), name, howto->name, +++ rel->r_addend, input_bfd, input_section, rel->r_offset); +++ break; +++ +++ case bfd_reloc_outofrange: +++ /* Stack state incorrect */ +++ loongarch_dump_reloc_record (info->callbacks->info); +++ info->callbacks->info +++ ("%X%H: Internal stack state is incorrect.\n" +++ "Want to push to full stack or pop from empty stack?\n", +++ input_bfd, input_section, rel->r_offset); +++ break; +++ +++ case bfd_reloc_notsupported: +++ info->callbacks->info +++ ("%X%H: Unknown relocation type.\n", +++ input_bfd, input_section, rel->r_offset); +++ break; +++ +++ default: +++ info->callbacks->info +++ ("%X%H: Internal: unknown error.\n", +++ input_bfd, input_section, rel->r_offset); +++ break; +++ } +++ +++ fatal = TRUE; +++ break; +++ } +++ +++ return !fatal; +++} +++ +++/* Finish up dynamic symbol handling. We set the contents of various +++ dynamic sections here. */ +++ +++static bfd_boolean +++loongarch_elf_finish_dynamic_symbol (bfd *output_bfd, +++ struct bfd_link_info *info, +++ struct elf_link_hash_entry *h, +++ Elf_Internal_Sym *sym) +++{ +++ struct loongarch_elf_link_hash_table *htab = loongarch_elf_hash_table (info); +++ const struct elf_backend_data *bed = get_elf_backend_data (output_bfd); +++ asection *plt = NULL; +++ +++ if (h->plt.offset != MINUS_ONE) +++ { +++ size_t i, plt_idx; +++ asection *gotplt, *relplt; +++ bfd_vma got_address; +++ uint32_t plt_entry[PLT_ENTRY_INSNS]; +++ bfd_byte *loc; +++ Elf_Internal_Rela rela; +++ +++ plt_idx = (h->plt.offset - PLT_HEADER_SIZE) / PLT_ENTRY_SIZE; +++ +++ /* one of '.plt' and '.iplt' represents */ +++ BFD_ASSERT (!!htab->elf.splt ^ !!htab->elf.iplt); +++ +++ if (htab->elf.splt) +++ { +++ BFD_ASSERT ((h->type == STT_GNU_IFUNC +++ && SYMBOL_REFERENCES_LOCAL (info, h)) +++ || h->dynindx != -1); +++ +++ plt = htab->elf.splt; +++ gotplt = htab->elf.sgotplt; +++ relplt = htab->elf.srelplt; +++ got_address = sec_addr (gotplt) + GOTPLT_HEADER_SIZE +++ + plt_idx * GOT_ENTRY_SIZE; +++ } +++ else /* if (htab->elf.iplt) */ +++ { +++ BFD_ASSERT (h->type == STT_GNU_IFUNC +++ && SYMBOL_REFERENCES_LOCAL (info, h)); +++ +++ plt = htab->elf.iplt; +++ gotplt = htab->elf.igotplt; +++ relplt = htab->elf.irelplt; +++ got_address = sec_addr (gotplt) +++ + plt_idx * GOT_ENTRY_SIZE; +++ } +++ +++ /* Find out where the .plt entry should go. */ +++ loc = plt->contents + h->plt.offset; +++ +++ /* Fill in the PLT entry itself. */ +++ loongarch_make_plt_entry +++ (got_address, sec_addr (plt) + h->plt.offset, plt_entry); +++ for (i = 0; i < PLT_ENTRY_INSNS; i++) +++ bfd_put_32 (output_bfd, plt_entry[i], loc + 4 * i); +++ +++ /* Fill in the initial value of the .got.plt entry. */ +++ loc = gotplt->contents + (got_address - sec_addr (gotplt)); +++ bfd_put_NN (output_bfd, sec_addr (plt), loc); +++ +++ rela.r_offset = got_address; +++ if (h->type == STT_GNU_IFUNC && SYMBOL_REFERENCES_LOCAL (info, h)) +++ { +++ rela.r_info = ELFNN_R_INFO (0, R_LARCH_IRELATIVE); +++ rela.r_addend = h->root.u.def.value +++ + h->root.u.def.section->output_section->vma +++ + h->root.u.def.section->output_offset; +++ } +++ else +++ { +++ /* Fill in the entry in the .rela.plt section. */ +++ rela.r_info = ELFNN_R_INFO (h->dynindx, R_LARCH_JUMP_SLOT); +++ rela.r_addend = 0; +++ } +++ +++ loc = relplt->contents + plt_idx * sizeof (ElfNN_External_Rela); +++ bed->s->swap_reloca_out (output_bfd, &rela, loc); +++ +++ if (!h->def_regular) +++ { +++ /* Mark the symbol as undefined, rather than as defined in +++ the .plt section. Leave the value alone. */ +++ sym->st_shndx = SHN_UNDEF; +++ /* If the symbol is weak, we do need to clear the value. +++ Otherwise, the PLT entry would provide a definition for +++ the symbol even if the symbol wasn't defined anywhere, +++ and so the symbol would never be NULL. */ +++ if (!h->ref_regular_nonweak) +++ sym->st_value = 0; +++ } +++ } +++ +++ if (h->got.offset != MINUS_ONE +++ +++ && /* TLS got entry have been handled in elf_relocate_section */ +++ !(loongarch_elf_hash_entry (h)->tls_type & (GOT_TLS_GD | GOT_TLS_IE)) +++ +++ && /* have allocated got entry but not allocated rela before */ +++ !UNDEFWEAK_NO_DYNAMIC_RELOC (info, h)) +++ { +++ asection *sgot, *srela; +++ Elf_Internal_Rela rela; +++ bfd_vma off = h->got.offset & ~(bfd_vma) 1; +++ +++ /* This symbol has an entry in the GOT. Set it up. */ +++ +++ sgot = htab->elf.sgot; +++ srela = htab->elf.srelgot; +++ BFD_ASSERT (sgot && srela); +++ +++ rela.r_offset = sec_addr (sgot) + off; +++ +++ if (h->type == STT_GNU_IFUNC) +++ { +++ if (/* 加入这个条件的原因是,对于静态链接,IRELATIVE重定位类型在 +++ __libc_start_main中调用apply_irel,通过链接脚本提供的 +++ __rela_iplt_start和__rela_iplt_end遍历.rela.iplt中的动态重定位 +++ 表项,来调用各个resolver并将返回结果写入.igot.plt中。 +++ 问题是照顾不到.rela.iplt之外的IRELATIVE重定位,因此我们在静态 +++ 连接的情况下绝对不将IRELATIVE写入.igot.plt之外。这样做在运行时 +++ 可能会有一些性能影响,毕竟ifunc函数都走plt,需要load两次 +++ got entry。没什么好的解决方法,未来可以搞.iplt2用于延迟调用 +++ resolver。 */ +++ elf_hash_table (info)->dynamic_sections_created +++ +++ && SYMBOL_REFERENCES_LOCAL (info, h)) +++ { +++ asection *sec = h->root.u.def.section; +++ rela.r_info = ELFNN_R_INFO (0, R_LARCH_IRELATIVE); +++ rela.r_addend = h->root.u.def.value +++ + sec->output_section->vma +++ + sec->output_offset; +++ bfd_put_NN (output_bfd, 0, sgot->contents + off); +++ } +++ else +++ { +++ BFD_ASSERT (plt); +++ rela.r_info = +++ ELFNN_R_INFO +++ (0, bfd_link_pic (info) ? R_LARCH_RELATIVE : R_LARCH_NONE); +++ rela.r_addend = plt->output_section->vma +++ + plt->output_offset +++ + h->plt.offset; +++ bfd_put_NN (output_bfd, rela.r_addend, sgot->contents + off); +++ } +++ } +++ else if (bfd_link_pic (info) && SYMBOL_REFERENCES_LOCAL (info, h)) +++ { +++ BFD_ASSERT (h->got.offset & 1/* has been filled in addr */); +++ asection *sec = h->root.u.def.section; +++ rela.r_info = ELFNN_R_INFO (0, R_LARCH_RELATIVE); +++ rela.r_addend = h->root.u.def.value +++ + sec->output_section->vma +++ + sec->output_offset; +++ } +++ else +++ { +++ BFD_ASSERT ((h->got.offset & 1) == 0); +++ BFD_ASSERT (h->dynindx != -1); +++ rela.r_info = ELFNN_R_INFO (h->dynindx, R_LARCH_NN); +++ rela.r_addend = 0; +++ } +++ +++ loongarch_elf_append_rela (output_bfd, srela, &rela); +++ } +++ +++ if (h->needs_copy) +++ { +++ Elf_Internal_Rela rela; +++ asection *s; +++ +++ /* This symbols needs a copy reloc. Set it up. */ +++ BFD_ASSERT (h->dynindx != -1); +++ +++ rela.r_offset = sec_addr (h->root.u.def.section) + h->root.u.def.value; +++ rela.r_info = ELFNN_R_INFO (h->dynindx, R_LARCH_COPY); +++ rela.r_addend = 0; +++ if (h->root.u.def.section == htab->elf.sdynrelro) +++ s = htab->elf.sreldynrelro; +++ else +++ s = htab->elf.srelbss; +++ loongarch_elf_append_rela (output_bfd, s, &rela); +++ } +++ +++ /* Mark some specially defined symbols as absolute. */ +++ if (h == htab->elf.hdynamic || h == htab->elf.hgot || h == htab->elf.hplt) +++ sym->st_shndx = SHN_ABS; +++ +++ return TRUE; +++} +++ +++/* Finish up the dynamic sections. */ +++ +++static bfd_boolean +++loongarch_finish_dyn (bfd *output_bfd, struct bfd_link_info *info, +++ bfd *dynobj, asection *sdyn) +++{ +++ struct loongarch_elf_link_hash_table *htab = loongarch_elf_hash_table (info); +++ const struct elf_backend_data *bed = get_elf_backend_data (output_bfd); +++ size_t dynsize = bed->s->sizeof_dyn, skipped_size = 0; +++ bfd_byte *dyncon, *dynconend; +++ +++ dynconend = sdyn->contents + sdyn->size; +++ for (dyncon = sdyn->contents; dyncon < dynconend; dyncon += dynsize) +++ { +++ Elf_Internal_Dyn dyn; +++ asection *s; +++ int skipped = 0; +++ +++ bed->s->swap_dyn_in (dynobj, dyncon, &dyn); +++ +++ switch (dyn.d_tag) +++ { +++ case DT_PLTGOT: +++ s = htab->elf.sgotplt; +++ dyn.d_un.d_ptr = s->output_section->vma + s->output_offset; +++ break; +++ case DT_JMPREL: +++ s = htab->elf.srelplt; +++ dyn.d_un.d_ptr = s->output_section->vma + s->output_offset; +++ break; +++ case DT_PLTRELSZ: +++ s = htab->elf.srelplt; +++ dyn.d_un.d_val = s->size; +++ break; +++ case DT_TEXTREL: +++ if ((info->flags & DF_TEXTREL) == 0) +++ skipped = 1; +++ break; +++ case DT_FLAGS: +++ if ((info->flags & DF_TEXTREL) == 0) +++ dyn.d_un.d_val &= ~DF_TEXTREL; +++ break; +++ } +++ if (skipped) +++ skipped_size += dynsize; +++ else +++ bed->s->swap_dyn_out (output_bfd, &dyn, dyncon - skipped_size); +++ } +++ /* Wipe out any trailing entries if we shifted down a dynamic tag. */ +++ memset (dyncon - skipped_size, 0, skipped_size); +++ return TRUE; +++} +++ +++/* Finish up local dynamic symbol handling. We set the contents of +++ various dynamic sections here. */ +++ +++static bfd_boolean +++elfNN_loongarch_finish_local_dynamic_symbol (void **slot, void *inf) +++{ +++ struct elf_link_hash_entry *h = (struct elf_link_hash_entry *) *slot; +++ struct bfd_link_info *info = (struct bfd_link_info *) inf; +++ +++ return loongarch_elf_finish_dynamic_symbol (info->output_bfd, info, h, NULL); +++} +++ +++static bfd_boolean +++loongarch_elf_finish_dynamic_sections (bfd *output_bfd, +++ struct bfd_link_info *info) +++{ +++ bfd *dynobj; +++ asection *sdyn, *plt, *gotplt; +++ struct loongarch_elf_link_hash_table *htab; +++ +++ htab = loongarch_elf_hash_table (info); +++ BFD_ASSERT (htab); +++ dynobj = htab->elf.dynobj; +++ sdyn = bfd_get_linker_section (dynobj, ".dynamic"); +++ +++ if (elf_hash_table (info)->dynamic_sections_created) +++ { +++ BFD_ASSERT (htab->elf.splt && sdyn); +++ +++ if (!loongarch_finish_dyn (output_bfd, info, dynobj, sdyn)) +++ return FALSE; +++ } +++ +++ if ((plt = htab->elf.splt)) +++ gotplt = htab->elf.sgotplt; +++ else if ((plt = htab->elf.iplt)) +++ gotplt = htab->elf.igotplt; +++ +++ if (plt && 0 < plt->size) +++ { +++ size_t i; +++ uint32_t plt_header[PLT_HEADER_INSNS]; +++ loongarch_make_plt_header (sec_addr (gotplt), sec_addr (plt), plt_header); +++ for (i = 0; i < PLT_HEADER_INSNS; i++) +++ bfd_put_32 (output_bfd, plt_header[i], plt->contents + 4 * i); +++ +++ elf_section_data (plt->output_section)->this_hdr.sh_entsize +++ = PLT_ENTRY_SIZE; +++ } +++ +++ if (htab->elf.sgotplt) +++ { +++ asection *output_section = htab->elf.sgotplt->output_section; +++ +++ if (bfd_is_abs_section (output_section)) +++ { +++ _bfd_error_handler +++ (_("discarded output section: `%pA'"), htab->elf.sgotplt); +++ return FALSE; +++ } +++ +++ if (0 < htab->elf.sgotplt->size) +++ { +++ /* Write the first two entries in .got.plt, needed for the dynamic +++ linker. */ +++ bfd_put_NN (output_bfd, MINUS_ONE, htab->elf.sgotplt->contents); +++ +++ /* 第二项非0时动态连接器认为它是plt header的地址,从而影响到所有 +++ R_LARCH_JUMP_SLOT。这似乎是为了prelink预留的。 */ +++ bfd_put_NN (output_bfd, (bfd_vma) 0, +++ htab->elf.sgotplt->contents + GOT_ENTRY_SIZE); +++ } +++ +++ elf_section_data (output_section)->this_hdr.sh_entsize = GOT_ENTRY_SIZE; +++ } +++ +++ if (htab->elf.sgot) +++ { +++ asection *output_section = htab->elf.sgot->output_section; +++ +++ if (0 < htab->elf.sgot->size) +++ { +++ /* Set the first entry in the global offset table to the address of +++ the dynamic section. */ +++ bfd_vma val = sdyn ? sec_addr (sdyn) : 0; +++ bfd_put_NN (output_bfd, val, htab->elf.sgot->contents); +++ } +++ +++ elf_section_data (output_section)->this_hdr.sh_entsize = GOT_ENTRY_SIZE; +++ } +++ +++ /* Fill PLT and GOT entries for local STT_GNU_IFUNC symbols. */ +++ htab_traverse +++ (htab->loc_hash_table, elfNN_loongarch_finish_local_dynamic_symbol, info); +++ +++ return TRUE; +++} +++ +++/* Return address for Ith PLT stub in section PLT, for relocation REL +++ or (bfd_vma) -1 if it should not be included. */ +++ +++static bfd_vma +++loongarch_elf_plt_sym_val (bfd_vma i, const asection *plt, +++ const arelent *rel ATTRIBUTE_UNUSED) +++{ +++ return plt->vma + PLT_HEADER_SIZE + i * PLT_ENTRY_SIZE; +++} +++ +++static enum elf_reloc_type_class +++loongarch_reloc_type_class (const struct bfd_link_info *info ATTRIBUTE_UNUSED, +++ const asection *rel_sec ATTRIBUTE_UNUSED, +++ const Elf_Internal_Rela *rela) +++{ +++ struct loongarch_elf_link_hash_table *htab; +++ htab = loongarch_elf_hash_table (info); +++ +++ if (htab->elf.dynsym != NULL +++ && htab->elf.dynsym->contents != NULL) +++ { +++ /* Check relocation against STT_GNU_IFUNC symbol if there are +++ dynamic symbols. +++ 一定要保证先完成非IFUNC重定位。因为如果IFUNC的resolover尚未完成 +++ 重定位,那么调用它返回的结果是错误的。非IFUNC重定位类型,比如R_LARCH_64 +++ 也可以携带IFUNC符号信息。我们在elf_machine_rela中可以察觉到一个符号是 +++ IFUNC,而在动态重定位时调用resolver。但八成这个resolver也需要一个 +++ R_LARCH_64重定位,可能还未完成,这时就会出问题。 +++ 在这里识别出来和STT_GNU_IFUNC相关的重定位,将他们往后排。 */ +++ bfd *abfd = info->output_bfd; +++ const struct elf_backend_data *bed = get_elf_backend_data (abfd); +++ unsigned long r_symndx = ELFNN_R_SYM (rela->r_info); +++ if (r_symndx != STN_UNDEF) +++ { +++ Elf_Internal_Sym sym; +++ if (!bed->s->swap_symbol_in (abfd, +++ htab->elf.dynsym->contents + r_symndx * bed->s->sizeof_sym, +++ 0, &sym)) +++ { +++ /* xgettext:c-format */ +++ _bfd_error_handler (_("%pB symbol number %lu references" +++ " nonexistent SHT_SYMTAB_SHNDX section"), +++ abfd, r_symndx); +++ /* Ideally an error class should be returned here. */ +++ } +++ else if (ELF_ST_TYPE (sym.st_info) == STT_GNU_IFUNC) +++ return reloc_class_ifunc; +++ } +++ } +++ +++ switch (ELFNN_R_TYPE (rela->r_info)) +++ { +++ case R_LARCH_IRELATIVE: +++ return reloc_class_ifunc; +++ case R_LARCH_RELATIVE: +++ return reloc_class_relative; +++ case R_LARCH_JUMP_SLOT: +++ return reloc_class_plt; +++ case R_LARCH_COPY: +++ return reloc_class_copy; +++ default: +++ return reloc_class_normal; +++ } +++} +++ +++ +++/* Copy the extra info we tack onto an elf_link_hash_entry. */ +++ +++static void +++loongarch_elf_copy_indirect_symbol (struct bfd_link_info *info, +++ struct elf_link_hash_entry *dir, +++ struct elf_link_hash_entry *ind) +++{ +++ struct loongarch_elf_link_hash_entry *edir, *eind; +++ +++ edir = (struct loongarch_elf_link_hash_entry *) dir; +++ eind = (struct loongarch_elf_link_hash_entry *) ind; +++ +++ if (eind->dyn_relocs != NULL) +++ { +++ if (edir->dyn_relocs != NULL) +++ { +++ struct elf_dyn_relocs **pp; +++ struct elf_dyn_relocs *p; +++ +++ /* Add reloc counts against the indirect sym to the direct sym +++ list. Merge any entries against the same section. */ +++ for (pp = &eind->dyn_relocs; (p = *pp) != NULL; ) +++ { +++ struct elf_dyn_relocs *q; +++ +++ for (q = edir->dyn_relocs; q != NULL; q = q->next) +++ if (q->sec == p->sec) +++ { +++ q->pc_count += p->pc_count; +++ q->count += p->count; +++ *pp = p->next; +++ break; +++ } +++ if (q == NULL) +++ pp = &p->next; +++ } +++ *pp = edir->dyn_relocs; +++ } +++ +++ edir->dyn_relocs = eind->dyn_relocs; +++ eind->dyn_relocs = NULL; +++ } +++ +++ if (ind->root.type == bfd_link_hash_indirect +++ && dir->got.refcount < 0) +++ { +++ edir->tls_type = eind->tls_type; +++ eind->tls_type = GOT_UNKNOWN; +++ } +++ _bfd_elf_link_hash_copy_indirect (info, dir, ind); +++} +++ +++//#if ARCH_SIZE == 32 +++//# define PRSTATUS_SIZE 0 /* FIXME */ +++//# define PRSTATUS_OFFSET_PR_CURSIG 0 +++//# define PRSTATUS_OFFSET_PR_PID 0 +++//# define PRSTATUS_OFFSET_PR_REG 0 +++//# define ELF_GREGSET_T_SIZE 264 +++//# define PRPSINFO_SIZE 0 +++//# define PRPSINFO_OFFSET_PR_PID 0 +++//# define PRPSINFO_OFFSET_PR_FNAME 0 +++//# define PRPSINFO_OFFSET_PR_PSARGS 0 +++//#else +++#define PRSTATUS_SIZE 384 +++#define PRSTATUS_OFFSET_PR_CURSIG 12 +++#define PRSTATUS_OFFSET_PR_PID 32 +++#define PRSTATUS_OFFSET_PR_REG 112 +++#define ELF_GREGSET_T_SIZE 264 +++ +++#define PRPSINFO_SIZE 144 +++#define PRPSINFO_OFFSET_PR_PID 32 +++#define PRPSINFO_OFFSET_PR_FNAME 48 +++#define PRPSINFO_OFFSET_PR_PSARGS 64 +++#define PRPSINFO_SIZE_PR_FNAMW 16 +++#define PRPSINFO_SIZE_PR_PSARGS 80 +++//#endif +++ +++/* Support for core dump NOTE sections. */ +++ +++static bfd_boolean +++loongarch_elf_grok_prstatus (bfd *abfd, Elf_Internal_Note *note) +++{ +++ switch (note->descsz) +++ { +++ default: +++ return FALSE; +++ +++ case PRSTATUS_SIZE: /* sizeof(struct elf_prstatus) on Linux/Loongarch. */ +++ /* pr_cursig */ +++ elf_tdata (abfd)->core->signal +++ = bfd_get_16 (abfd, note->descdata + PRSTATUS_OFFSET_PR_CURSIG); +++ +++ /* pr_pid */ +++ elf_tdata (abfd)->core->lwpid +++ = bfd_get_32 (abfd, note->descdata + PRSTATUS_OFFSET_PR_PID); +++ break; +++ } +++ +++ /* Make a ".reg/999" section. */ +++ return _bfd_elfcore_make_pseudosection (abfd, ".reg", ELF_GREGSET_T_SIZE, +++ note->descpos + PRSTATUS_OFFSET_PR_REG); +++} +++ +++static bfd_boolean +++loongarch_elf_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) +++{ +++ switch (note->descsz) +++ { +++ default: +++ return FALSE; +++ +++ case PRPSINFO_SIZE: /* sizeof(struct elf_prpsinfo) on Linux/Loongarch. */ +++ /* pr_pid */ +++ elf_tdata (abfd)->core->pid +++ = bfd_get_32 (abfd, note->descdata + PRPSINFO_OFFSET_PR_PID); +++ +++ /* pr_fname */ +++ elf_tdata (abfd)->core->program = _bfd_elfcore_strndup +++ (abfd, note->descdata + PRPSINFO_OFFSET_PR_FNAME, PRPSINFO_OFFSET_PR_FNAME); +++ +++ /* pr_psargs */ +++ elf_tdata (abfd)->core->command = _bfd_elfcore_strndup +++ (abfd, note->descdata + PRPSINFO_OFFSET_PR_PSARGS, PRPSINFO_SIZE_PR_PSARGS); +++ break; +++ } +++ +++ /* Note that for some reason, a spurious space is tacked +++ onto the end of the args in some (at least one anyway) +++ implementations, so strip it off if it exists. */ +++ +++ { +++ char *command = elf_tdata (abfd)->core->command; +++ int n = strlen (command); +++ +++ if (0 < n && command[n - 1] == ' ') +++ command[n - 1] = '\0'; +++ } +++ +++ return TRUE; +++} +++ +++/* Set the right mach type. */ +++static bfd_boolean +++loongarch_elf_object_p (bfd *abfd) +++{ +++ /* There are only two mach types in Loongarch currently. */ +++ if (strcmp (abfd->xvec->name, "elf64-loongarch") == 0) +++ bfd_default_set_arch_mach (abfd, bfd_arch_loongarch, bfd_mach_loongarch64); +++ else +++ bfd_default_set_arch_mach (abfd, bfd_arch_loongarch, bfd_mach_loongarch32); +++ return TRUE; +++} +++ +++static asection * +++loongarch_elf_gc_mark_hook (asection *sec, +++ struct bfd_link_info *info, +++ Elf_Internal_Rela *rel, +++ struct elf_link_hash_entry *h, +++ Elf_Internal_Sym *sym) +++{ +++ if (h != NULL) +++ switch (ELFNN_R_TYPE (rel->r_info)) +++ { +++ case R_LARCH_GNU_VTINHERIT: +++ case R_LARCH_GNU_VTENTRY: +++ return NULL; +++ } +++ +++ return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym); +++} +++ +++static bfd_boolean +++_loongarch_bfd_set_section_contents(bfd *abfd, +++ sec_ptr section, +++ const void *location, +++ file_ptr offset, +++ bfd_size_type conut) +++ +++{ +++ if (elf_elfheader(abfd)->e_flags ==0) +++ if(abfd->arch_info->arch == bfd_arch_loongarch) +++ if (abfd->arch_info->mach ==bfd_mach_loongarch32) +++ elf_elfheader(abfd)->e_flags = EF_LARCH_ABI_LP32; +++ else if (abfd->arch_info->mach ==bfd_mach_loongarch64) +++ elf_elfheader(abfd)->e_flags = EF_LARCH_ABI_LP64; +++ else +++ return FALSE; +++ return _bfd_elf_set_section_contents(abfd,section,location,offset,conut); +++} +++ +++ +++ +++#define TARGET_LITTLE_SYM loongarch_elfNN_vec +++#define TARGET_LITTLE_NAME "elfNN-loongarch" +++#define ELF_ARCH bfd_arch_loongarch +++#define ELF_TARGET_ID LARCH_ELF_DATA +++#define ELF_MACHINE_CODE EM_LOONGARCH +++#define ELF_MAXPAGESIZE 0x4000 +++#define bfd_elfNN_bfd_reloc_type_lookup loongarch_reloc_type_lookup +++#define bfd_elfNN_bfd_link_hash_table_create loongarch_elf_link_hash_table_create +++#define bfd_elfNN_bfd_reloc_name_lookup loongarch_reloc_name_lookup +++#define elf_info_to_howto_rel NULL /* fall through to elf_info_to_howto */ +++#define elf_info_to_howto loongarch_info_to_howto_rela +++#define bfd_elfNN_bfd_merge_private_bfd_data \ +++ _bfd_loongarch_elf_merge_private_bfd_data +++ +++#define bfd_elfNN_set_section_contents _loongarch_bfd_set_section_contents +++ +++ +++#define elf_backend_reloc_type_class loongarch_reloc_type_class +++#define elf_backend_copy_indirect_symbol loongarch_elf_copy_indirect_symbol +++#define elf_backend_create_dynamic_sections loongarch_elf_create_dynamic_sections +++#define elf_backend_check_relocs loongarch_elf_check_relocs +++#define elf_backend_adjust_dynamic_symbol loongarch_elf_adjust_dynamic_symbol +++#define elf_backend_size_dynamic_sections loongarch_elf_size_dynamic_sections +++#define elf_backend_relocate_section loongarch_elf_relocate_section +++#define elf_backend_finish_dynamic_symbol loongarch_elf_finish_dynamic_symbol +++#define elf_backend_finish_dynamic_sections loongarch_elf_finish_dynamic_sections +++#define elf_backend_object_p loongarch_elf_object_p +++#define elf_backend_gc_mark_hook loongarch_elf_gc_mark_hook +++#define elf_backend_plt_sym_val loongarch_elf_plt_sym_val +++#define elf_backend_grok_prstatus loongarch_elf_grok_prstatus +++#define elf_backend_grok_psinfo loongarch_elf_grok_psinfo +++ +++#include "elfNN-target.h" ++diff --git gdb-10.2/bfd/elfxx-loongarch.c gdb-10.2/bfd/elfxx-loongarch.c ++new file mode 100644 ++index 0000000..3f8534b ++--- /dev/null +++++ gdb-10.2/bfd/elfxx-loongarch.c ++@@ -0,0 +1,172 @@ +++#include "sysdep.h" +++#include "bfd.h" +++#include "libbfd.h" +++#include "elf-bfd.h" +++#include "elf/loongarch.h" +++#include "elfxx-loongarch.h" +++ +++ +++ +++/* This does not include any relocation information, but should be +++ good enough for GDB or objdump to read the file. */ +++ +++static reloc_howto_type howto_table[] = +++{ +++#define LOONGARCH_HOWTO(r_name) HOWTO (R_LARCH_##r_name,0,3,32,FALSE,0,complain_overflow_signed,bfd_elf_generic_reloc,"R_LARCH_"#r_name,FALSE,0,0,FALSE) +++LOONGARCH_HOWTO (NONE), +++LOONGARCH_HOWTO (32), +++LOONGARCH_HOWTO (64), +++LOONGARCH_HOWTO (RELATIVE), +++LOONGARCH_HOWTO (COPY), +++LOONGARCH_HOWTO (JUMP_SLOT), +++LOONGARCH_HOWTO (TLS_DTPMOD32), +++LOONGARCH_HOWTO (TLS_DTPMOD64), +++LOONGARCH_HOWTO (TLS_DTPREL32), +++LOONGARCH_HOWTO (TLS_DTPREL64), +++LOONGARCH_HOWTO (TLS_TPREL32), +++LOONGARCH_HOWTO (TLS_TPREL64), +++LOONGARCH_HOWTO (IRELATIVE), +++ +++LOONGARCH_HOWTO (MARK_LA), +++LOONGARCH_HOWTO (MARK_PCREL), +++ HOWTO (R_LARCH_SOP_PUSH_PCREL, /* type */ +++ 2, /* rightshift */ +++ 3, /* size */ +++ 32, /* bitsize */ +++ TRUE/* FIXME: somewhat use this */, /* pc_relative */ +++ 0, /* bitpos */ +++ complain_overflow_signed, /* complain_on_overflow */ +++ bfd_elf_generic_reloc, /* special_function */ +++ "R_LARCH_SOP_PUSH_PCREL", /* name */ +++ FALSE, /* partial_inplace */ +++ 0x03ffffff, /* src_mask */ +++ 0x03ffffff, /* dst_mask */ +++ FALSE), /* pcrel_offset */ +++LOONGARCH_HOWTO (SOP_PUSH_ABSOLUTE), +++LOONGARCH_HOWTO (SOP_PUSH_DUP), +++LOONGARCH_HOWTO (SOP_PUSH_GPREL), +++LOONGARCH_HOWTO (SOP_PUSH_TLS_TPREL), +++LOONGARCH_HOWTO (SOP_PUSH_TLS_GOT), +++LOONGARCH_HOWTO (SOP_PUSH_TLS_GD), +++LOONGARCH_HOWTO (SOP_PUSH_PLT_PCREL), +++LOONGARCH_HOWTO (SOP_ASSERT), +++LOONGARCH_HOWTO (SOP_NOT), +++LOONGARCH_HOWTO (SOP_SUB), +++LOONGARCH_HOWTO (SOP_SL), +++LOONGARCH_HOWTO (SOP_SR), +++LOONGARCH_HOWTO (SOP_ADD), +++LOONGARCH_HOWTO (SOP_AND), +++LOONGARCH_HOWTO (SOP_IF_ELSE), +++LOONGARCH_HOWTO (SOP_POP_32_S_10_5), +++LOONGARCH_HOWTO (SOP_POP_32_U_10_12), +++LOONGARCH_HOWTO (SOP_POP_32_S_10_12), +++LOONGARCH_HOWTO (SOP_POP_32_S_10_16), +++LOONGARCH_HOWTO (SOP_POP_32_S_10_16_S2), +++LOONGARCH_HOWTO (SOP_POP_32_S_5_20), +++LOONGARCH_HOWTO (SOP_POP_32_S_0_5_10_16_S2), +++LOONGARCH_HOWTO (SOP_POP_32_S_0_10_10_16_S2), +++LOONGARCH_HOWTO (SOP_POP_32_U), +++LOONGARCH_HOWTO (ADD8), +++LOONGARCH_HOWTO (ADD16), +++LOONGARCH_HOWTO (ADD24), +++LOONGARCH_HOWTO (ADD32), +++LOONGARCH_HOWTO (ADD64), +++LOONGARCH_HOWTO (SUB8), +++LOONGARCH_HOWTO (SUB16), +++LOONGARCH_HOWTO (SUB24), +++LOONGARCH_HOWTO (SUB32), +++LOONGARCH_HOWTO (SUB64), +++}; +++ +++struct elf_reloc_map +++{ +++ bfd_reloc_code_real_type bfd_val; +++ enum elf_loongarch_reloc_type elf_val; +++}; +++ +++static const struct elf_reloc_map loong_reloc_map[] = +++{ +++ { BFD_RELOC_NONE, R_LARCH_NONE }, +++ { BFD_RELOC_32, R_LARCH_32 }, +++ { BFD_RELOC_64, R_LARCH_64 }, +++ +++#define LOONGARCH_reloc_map(r_name) {BFD_RELOC_LARCH_##r_name,R_LARCH_##r_name} +++LOONGARCH_reloc_map (TLS_DTPMOD32), +++LOONGARCH_reloc_map (TLS_DTPMOD64), +++LOONGARCH_reloc_map (TLS_DTPREL32), +++LOONGARCH_reloc_map (TLS_DTPREL64), +++LOONGARCH_reloc_map (TLS_TPREL32), +++LOONGARCH_reloc_map (TLS_TPREL64), +++ +++LOONGARCH_reloc_map (MARK_LA), +++LOONGARCH_reloc_map (MARK_PCREL), +++LOONGARCH_reloc_map (SOP_PUSH_PCREL), +++LOONGARCH_reloc_map (SOP_PUSH_ABSOLUTE), +++LOONGARCH_reloc_map (SOP_PUSH_DUP), +++LOONGARCH_reloc_map (SOP_PUSH_GPREL), +++LOONGARCH_reloc_map (SOP_PUSH_TLS_TPREL), +++LOONGARCH_reloc_map (SOP_PUSH_TLS_GOT), +++LOONGARCH_reloc_map (SOP_PUSH_TLS_GD), +++LOONGARCH_reloc_map (SOP_PUSH_PLT_PCREL), +++LOONGARCH_reloc_map (SOP_ASSERT), +++LOONGARCH_reloc_map (SOP_NOT), +++LOONGARCH_reloc_map (SOP_SUB), +++LOONGARCH_reloc_map (SOP_SL), +++LOONGARCH_reloc_map (SOP_SR), +++LOONGARCH_reloc_map (SOP_ADD), +++LOONGARCH_reloc_map (SOP_AND), +++LOONGARCH_reloc_map (SOP_IF_ELSE), +++LOONGARCH_reloc_map (SOP_POP_32_S_10_5), +++LOONGARCH_reloc_map (SOP_POP_32_U_10_12), +++LOONGARCH_reloc_map (SOP_POP_32_S_10_12), +++LOONGARCH_reloc_map (SOP_POP_32_S_10_16), +++LOONGARCH_reloc_map (SOP_POP_32_S_10_16_S2), +++LOONGARCH_reloc_map (SOP_POP_32_S_5_20), +++LOONGARCH_reloc_map (SOP_POP_32_S_0_5_10_16_S2), +++LOONGARCH_reloc_map (SOP_POP_32_S_0_10_10_16_S2), +++LOONGARCH_reloc_map (SOP_POP_32_U), +++LOONGARCH_reloc_map (ADD8), +++LOONGARCH_reloc_map (ADD16), +++LOONGARCH_reloc_map (ADD24), +++LOONGARCH_reloc_map (ADD32), +++LOONGARCH_reloc_map (ADD64), +++LOONGARCH_reloc_map (SUB8), +++LOONGARCH_reloc_map (SUB16), +++LOONGARCH_reloc_map (SUB24), +++LOONGARCH_reloc_map (SUB32), +++LOONGARCH_reloc_map (SUB64), +++}; +++ +++reloc_howto_type * +++loongarch_elf_rtype_to_howto (unsigned int r_type) +++{ +++ size_t i; +++ for (i = 0; i < ARRAY_SIZE (howto_table); i++) +++ if (howto_table[i].type == r_type) +++ return &howto_table[i]; +++ return NULL; +++} +++ +++reloc_howto_type * +++loongarch_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, bfd_reloc_code_real_type code) +++{ +++ unsigned int i; +++ for (i = 0; i < ARRAY_SIZE (loong_reloc_map); i++) +++ if (loong_reloc_map[i].bfd_val == code) +++ return loongarch_elf_rtype_to_howto ((int) loong_reloc_map[i].elf_val); +++ // return &howto_table[(int) loong_reloc_map[i].elf_val]; +++ +++ return NULL; +++} +++ +++reloc_howto_type * +++loongarch_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name) +++{ +++ unsigned int i; +++ +++ for (i = 0; i < ARRAY_SIZE (howto_table); i++) +++ if (howto_table[i].name && strcasecmp (howto_table[i].name, r_name) == 0) +++ return &howto_table[i]; +++ +++ return NULL; +++} ++diff --git gdb-10.2/bfd/elfxx-loongarch.h gdb-10.2/bfd/elfxx-loongarch.h ++new file mode 100644 ++index 0000000..0e98086 ++--- /dev/null +++++ gdb-10.2/bfd/elfxx-loongarch.h ++@@ -0,0 +1,11 @@ +++#include "elf/common.h" +++#include "elf/internal.h" +++ +++extern reloc_howto_type * +++loongarch_elf_rtype_to_howto (unsigned int r_type); +++ +++extern reloc_howto_type * +++loongarch_reloc_type_lookup (bfd *abfd, bfd_reloc_code_real_type code); +++ +++extern reloc_howto_type * +++loongarch_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name); ++diff --git gdb-10.2/bfd/libbfd.h gdb-10.2/bfd/libbfd.h ++index 74d7e41..c8b9131 100644 ++--- gdb-10.2/bfd/libbfd.h +++++ gdb-10.2/bfd/libbfd.h ++@@ -3330,6 +3330,49 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@", ++ "BFD_RELOC_WASM32_CODE_POINTER", ++ "BFD_RELOC_WASM32_INDEX", ++ "BFD_RELOC_WASM32_PLT_SIG", +++ "BFD_RELOC_LARCH_TLS_DTPMOD32", +++ "BFD_RELOC_LARCH_TLS_DTPREL32", +++ "BFD_RELOC_LARCH_TLS_DTPMOD64", +++ "BFD_RELOC_LARCH_TLS_DTPREL64", +++ "BFD_RELOC_LARCH_TLS_TPREL32", +++ "BFD_RELOC_LARCH_TLS_TPREL64", +++ "BFD_RELOC_LARCH_MARK_LA", +++ "BFD_RELOC_LARCH_MARK_PCREL", +++ "BFD_RELOC_LARCH_SOP_PUSH_PCREL", +++ "BFD_RELOC_LARCH_SOP_PUSH_ABSOLUTE", +++ "BFD_RELOC_LARCH_SOP_PUSH_DUP", +++ "BFD_RELOC_LARCH_SOP_PUSH_GPREL", +++ "BFD_RELOC_LARCH_SOP_PUSH_TLS_TPREL", +++ "BFD_RELOC_LARCH_SOP_PUSH_TLS_GOT", +++ "BFD_RELOC_LARCH_SOP_PUSH_TLS_GD", +++ "BFD_RELOC_LARCH_SOP_PUSH_PLT_PCREL", +++ "BFD_RELOC_LARCH_SOP_ASSERT", +++ "BFD_RELOC_LARCH_SOP_NOT", +++ "BFD_RELOC_LARCH_SOP_SUB", +++ "BFD_RELOC_LARCH_SOP_SL", +++ "BFD_RELOC_LARCH_SOP_SR", +++ "BFD_RELOC_LARCH_SOP_ADD", +++ "BFD_RELOC_LARCH_SOP_AND", +++ "BFD_RELOC_LARCH_SOP_IF_ELSE", +++ "BFD_RELOC_LARCH_SOP_POP_32_S_10_5", +++ "BFD_RELOC_LARCH_SOP_POP_32_U_10_12", +++ "BFD_RELOC_LARCH_SOP_POP_32_S_10_12", +++ "BFD_RELOC_LARCH_SOP_POP_32_S_10_16", +++ "BFD_RELOC_LARCH_SOP_POP_32_S_10_16_S2", +++ "BFD_RELOC_LARCH_SOP_POP_32_S_5_20", +++ "BFD_RELOC_LARCH_SOP_POP_32_S_0_5_10_16_S2", +++ "BFD_RELOC_LARCH_SOP_POP_32_S_0_10_10_16_S2", +++ "BFD_RELOC_LARCH_SOP_POP_32_U", +++ "BFD_RELOC_LARCH_ADD8", +++ "BFD_RELOC_LARCH_ADD16", +++ "BFD_RELOC_LARCH_ADD24", +++ "BFD_RELOC_LARCH_ADD32", +++ "BFD_RELOC_LARCH_ADD64", +++ "BFD_RELOC_LARCH_SUB8", +++ "BFD_RELOC_LARCH_SUB16", +++ "BFD_RELOC_LARCH_SUB24", +++ "BFD_RELOC_LARCH_SUB32", +++ "BFD_RELOC_LARCH_SUB64", ++ "BFD_RELOC_CKCORE_NONE", ++ "BFD_RELOC_CKCORE_ADDR32", ++ "BFD_RELOC_CKCORE_PCREL_IMM8BY4", ++diff --git gdb-10.2/bfd/reloc.c gdb-10.2/bfd/reloc.c ++index dc923fe..4ff8b95 100644 ++--- gdb-10.2/bfd/reloc.c +++++ gdb-10.2/bfd/reloc.c ++@@ -8142,6 +8142,95 @@ ENUM ++ ENUMDOC ++ S12Z relocations. ++ +++ENUM +++ BFD_RELOC_LARCH_TLS_DTPMOD32 +++ENUMX +++ BFD_RELOC_LARCH_TLS_DTPREL32 +++ENUMX +++ BFD_RELOC_LARCH_TLS_DTPMOD64 +++ENUMX +++ BFD_RELOC_LARCH_TLS_DTPREL64 +++ENUMX +++ BFD_RELOC_LARCH_TLS_TPREL32 +++ENUMX +++ BFD_RELOC_LARCH_TLS_TPREL64 +++ENUMX +++ BFD_RELOC_LARCH_MARK_LA +++ENUMX +++ BFD_RELOC_LARCH_MARK_PCREL +++ENUMX +++ BFD_RELOC_LARCH_SOP_PUSH_PCREL +++ENUMX +++ BFD_RELOC_LARCH_SOP_PUSH_ABSOLUTE +++ENUMX +++ BFD_RELOC_LARCH_SOP_PUSH_DUP +++ENUMX +++ BFD_RELOC_LARCH_SOP_PUSH_GPREL +++ENUMX +++ BFD_RELOC_LARCH_SOP_PUSH_TLS_TPREL +++ENUMX +++ BFD_RELOC_LARCH_SOP_PUSH_TLS_GOT +++ENUMX +++ BFD_RELOC_LARCH_SOP_PUSH_TLS_GD +++ENUMX +++ BFD_RELOC_LARCH_SOP_PUSH_PLT_PCREL +++ENUMX +++ BFD_RELOC_LARCH_SOP_ASSERT +++ENUMX +++ BFD_RELOC_LARCH_SOP_NOT +++ENUMX +++ BFD_RELOC_LARCH_SOP_SUB +++ENUMX +++ BFD_RELOC_LARCH_SOP_SL +++ENUMX +++ BFD_RELOC_LARCH_SOP_SR +++ENUMX +++ BFD_RELOC_LARCH_SOP_ADD +++ENUMX +++ BFD_RELOC_LARCH_SOP_AND +++ENUMX +++ BFD_RELOC_LARCH_SOP_IF_ELSE +++ENUMX +++ BFD_RELOC_LARCH_SOP_POP_32_S_10_5 +++ENUMX +++ BFD_RELOC_LARCH_SOP_POP_32_U_10_12 +++ENUMX +++ BFD_RELOC_LARCH_SOP_POP_32_S_10_12 +++ENUMX +++ BFD_RELOC_LARCH_SOP_POP_32_S_10_16 +++ENUMX +++ BFD_RELOC_LARCH_SOP_POP_32_S_10_16_S2 +++ENUMX +++ BFD_RELOC_LARCH_SOP_POP_32_S_5_20 +++ENUMX +++ BFD_RELOC_LARCH_SOP_POP_32_S_0_5_10_16_S2 +++ENUMX +++ BFD_RELOC_LARCH_SOP_POP_32_S_0_10_10_16_S2 +++ENUMX +++ BFD_RELOC_LARCH_SOP_POP_32_U +++ENUMX +++ BFD_RELOC_LARCH_ADD8 +++ENUMX +++ BFD_RELOC_LARCH_ADD16 +++ENUMX +++ BFD_RELOC_LARCH_ADD24 +++ENUMX +++ BFD_RELOC_LARCH_ADD32 +++ENUMX +++ BFD_RELOC_LARCH_ADD64 +++ENUMX +++ BFD_RELOC_LARCH_SUB8 +++ENUMX +++ BFD_RELOC_LARCH_SUB16 +++ENUMX +++ BFD_RELOC_LARCH_SUB24 +++ENUMX +++ BFD_RELOC_LARCH_SUB32 +++ENUMX +++ BFD_RELOC_LARCH_SUB64 +++ENUMDOC +++ LoongISA relocations. +++ ++ ENDSENUM ++ BFD_RELOC_UNUSED ++ CODE_FRAGMENT ++diff --git gdb-10.2/bfd/targets.c gdb-10.2/bfd/targets.c ++index 35492b9..27f698b 100644 ++--- gdb-10.2/bfd/targets.c +++++ gdb-10.2/bfd/targets.c ++@@ -759,6 +759,8 @@ extern const bfd_target l1om_elf64_vec; ++ extern const bfd_target l1om_elf64_fbsd_vec; ++ extern const bfd_target lm32_elf32_vec; ++ extern const bfd_target lm32_elf32_fdpic_vec; +++extern const bfd_target loongarch_elf32_vec; +++extern const bfd_target loongarch_elf64_vec; ++ extern const bfd_target m32c_elf32_vec; ++ extern const bfd_target m32r_elf32_vec; ++ extern const bfd_target m32r_elf32_le_vec; ++@@ -1117,6 +1119,11 @@ static const bfd_target * const _bfd_target_vector[] = ++ ++ &lm32_elf32_vec, ++ +++#ifdef BFD64 +++ &loongarch_elf32_vec, +++ &loongarch_elf64_vec, +++#endif +++ ++ &m32c_elf32_vec, ++ ++ &m32r_elf32_vec, ++diff --git gdb-10.2/config.guess gdb-10.2/config.guess ++index 45001cf..ccc5416 100755 ++--- gdb-10.2/config.guess +++++ gdb-10.2/config.guess ++@@ -925,6 +925,9 @@ EOF ++ UNAME_MACHINE=aarch64_be ++ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" ++ exit ;; +++ loongarch32:Linux:*:* | loongarch64:Linux:*:* | loongarchx32:Linux:*:*) +++ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" +++ exit ;; ++ alpha:Linux:*:*) ++ case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' /proc/cpuinfo 2>/dev/null` in ++ EV5) UNAME_MACHINE=alphaev5 ;; ++diff --git gdb-10.2/config.sub gdb-10.2/config.sub ++index f02d43a..ab2c038 100755 ++--- gdb-10.2/config.sub +++++ gdb-10.2/config.sub ++@@ -1157,6 +1157,7 @@ case $cpu-$vendor in ++ 1750a | 580 \ ++ | a29k \ ++ | aarch64 | aarch64_be \ +++ | loongarch32 | loongarch64 | loongarchx32 \ ++ | abacus \ ++ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] \ ++ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] \ ++diff --git gdb-10.2/gdb/arch/loongarch-insn.h gdb-10.2/gdb/arch/loongarch-insn.h ++new file mode 100644 ++index 0000000..3328dff ++--- /dev/null +++++ gdb-10.2/gdb/arch/loongarch-insn.h ++@@ -0,0 +1,352 @@ +++#ifndef ARCH_LOONGARCH_INSN_H +++#define ARCH_LOONGARCH_INSN_H +++ +++#define insmask(x) (0xffffffff << (32 - (x))) +++ +++#define funccode(ins,x) ((ins) & insmask(x)) +++ +++enum loongarch_opcodes +++{ +++ INS_JIRL = 0x4c000000, +++ INS_BL = 0x54000000, +++ INS_MOVFR2GRS = 0x0114b400, +++ INS_MOVFR2GRD = 0x0114b800, +++ INS_MOVFRH2GRS = 0x0114bc00, +++ INS_MOVFCSR2GR = 0x0114c800, +++ INS_MOVCF2GR = 0x0114dc00, +++ INS_MOVGR2FCSR = 0x0114c000, +++ INS_MOVFR2CF = 0x0114d000, +++ INS_MOVGR2CF = 0x0114d800, +++ INS_STB = 0x29000000, +++ INS_STH = 0x29400000, +++ INS_STW = 0x29800000, +++ INS_STD = 0x29c00000, +++ INS_STXB = 0x38100000, +++ INS_STXH = 0x38140000, +++ INS_STXW = 0x38180000, +++ INS_STXD = 0x381c0000, +++ INS_STPTRW = 0x25000000, +++ INS_STPTRD = 0x27000000, +++ INS_SCW = 0x21000000, +++ INS_SCD = 0x23000000, +++ INS_FSTS = 0x2b400000, +++ INS_FSTD = 0x2bc00000, +++ INS_FSTXS = 0x38380000, +++ INS_FSTXD = 0x383c0000, +++ INS_LDGT = 0x38780000, +++ INS_LDLE = 0x387a0000, +++ INS_FLDGT = 0x38740000, +++ INS_FLDLE = 0x38750000, +++ INS_STGT = 0x387c0000, +++ INS_STLE = 0x387e0000, +++ INS_FSTGT = 0x38760000, +++ INS_FSTLE = 0x38770000, +++ INS_ARITH_IMM = 0x02000000, +++ INS_ARITH_IMM_2 = 0x10000000, +++ INS_ARITH = 0x00100000, +++ INS_DIV_MOD = 0x00200000, +++ INS_SHIFT = 0x00400000, +++ INS_LLW = 0x20000000, +++ INS_LLD = 0x22000000, +++ INS_LDPTRW = 0x24000000, +++ INS_LDPTRD = 0x26000000, +++ INS_LD = 0x28000000, +++ INS_LDBU = 0x2a000000, +++ INS_LDHU = 0x2a400000, +++ INS_LDWU = 0x2a800000, +++ INS_LDXB = 0x38000000, +++ INS_LDXH = 0x38040000, +++ INS_LDXW = 0x38080000, +++ INS_LDXD = 0x380c0000, +++ INS_CLOZ_W = 0x00001000, +++ INS_CLOZ_D = 0x00002000, +++ INS_REVB = 0x00003000, +++ INS_REVH = 0x00004000, +++ INS_BITREVB = 0x00004800, +++ INS_BITREVWD = 0x00005000, +++ INS_EXT = 0x00005800, +++ INS_CPUCFG = 0x00006c00, +++ INS_ALSLW = 0x00040000, +++ INS_ALSLD = 0x002c0000, +++ INS_BYTEPICK = 0x00080000, +++ INS_CRC = 0x00240000, +++ INS_SLLIW = 0x00408000, +++ INS_SLLID = 0x00410000, +++ INS_SRLIW = 0x00448000, +++ INS_SRLID = 0x00450000, +++ INS_SRAIW = 0x00488000, +++ INS_SRAID = 0x00490000, +++ INS_ROTRIW = 0x004c8000, +++ INS_ROTRID = 0x004d0000, +++ INS_BSTR_W = 0x00600000, +++ INS_BSTR_D = 0x00800000, +++ INS_LDDIR = 0x06400000, +++ INS_JUMP = 0x40000000, +++ INS_ST = 0x29000000, +++ INS_RDTIMELW = 0x00006000, +++ INS_RDTIMEHW = 0x00006400, +++ INS_RDTIMED = 0x00006800, +++ INS_FLOAT_ARITH = 0x01000000, +++ INS_FLOAT_MUL = 0x08000000, +++ INS_FLDS = 0x2b000000, +++ INS_FLDD = 0x2b800000, +++ INS_FLDXS = 0x38300000, +++ INS_FLDXD = 0x38340000, +++ INS_SIGNED_AM = 0x38600000, +++ INS_UNSIGNED_AM = 0x38700000, +++ INS_COND_FLD = 0x38740000, +++ INS_COND_LD = 0x38780000, +++ INS_COND_FST = 0x38760000, +++ INS_COND_ST = 0x387c0000, +++ INS_CACOP = 0x06000000, +++ INS_TLBCLR = 0x06482000, +++ INS_TLBFLUSH = 0x06482400, +++ INS_TLBWR = 0x06483000, +++ INS_TLBFILL = 0x06483400, +++ INS_INVTLB = 0x06498000, +++ INS_IDLE = 0x06488000, +++ INS_PRELD = 0x2ac00000, +++ INS_PRELDX = 0x382c0000, +++ INS_DBAR = 0x38720000, +++ INS_IBAR = 0x38728000, +++ INS_FCMPCONDS = 0x0c100000, +++ INS_FCMPCONDD = 0x0c200000, +++ INS_SYSCALL = 0x002b0000, +++}; +++ +++enum loongarch_opcode_mask_bit +++{ +++ MASK_JIRL = 6, +++ MASK_BL = 6, +++ MASK_MOVFR2GRS = 22, +++ MASK_MOVFR2GRD = 22, +++ MASK_MOVFRH2GRS = 22, +++ MASK_MOVFCSR2GR = 22, +++ MASK_MOVCF2GR = 24, +++ MASK_MOVGR2FCSR = 22, +++ MASK_MOVFR2CF = 22, +++ MASK_MOVGR2CF = 22, +++ MASK_STB = 12, +++ MASK_STH = 10, +++ MASK_STW = 10, +++ MASK_STD = 10, +++ MASK_STXB = 17, +++ MASK_STXH = 17, +++ MASK_STXW = 17, +++ MASK_STXD = 17, +++ MASK_STPTRW = 8, +++ MASK_STPTRD = 8, +++ MASK_SCW = 8, +++ MASK_SCD = 8, +++ MASK_FSTS = 10, +++ MASK_FSTD = 10, +++ MASK_FSTXS = 17, +++ MASK_FSTXD = 17, +++ MASK_LDGT = 15, +++ MASK_LDLE = 15, +++ MASK_FLDGT = 16, +++ MASK_FLDLE = 16, +++ MASK_STGT = 15, +++ MASK_STLE = 15, +++ MASK_FSTGT = 16, +++ MASK_FSTLE = 16, +++ MASK_ARITH_IMM = 7, +++ MASK_ARITH_IMM_2 = 4, +++ MASK_ARITH = 12, +++ MASK_DIV_MOD = 14, +++ MASK_SHIFT = 10, +++ MASK_LLW = 8, +++ MASK_LLD = 8, +++ MASK_LDPTRW = 8, +++ MASK_LDPTRD = 8, +++ MASK_LD = 8, +++ MASK_LDBU = 10, +++ MASK_LDHU = 10, +++ MASK_LDWU = 10, +++ MASK_LDXB = 17, +++ MASK_LDXH = 17, +++ MASK_LDXW = 17, +++ MASK_LDXD = 17, +++ MASK_CLOZ_W = 20, +++ MASK_CLOZ_D = 20, +++ MASK_REVB = 20, +++ MASK_REVH = 21, +++ MASK_BITREVB = 21, +++ MASK_BITREVWD = 21, +++ MASK_EXT = 21, +++ MASK_CPUCFG = 22, +++ MASK_ALSLW = 14, +++ MASK_ALSLD = 15, +++ MASK_BYTEPICK = 13, +++ MASK_CRC = 14, +++ MASK_SLLIW = 17, +++ MASK_SLLID = 16, +++ MASK_SRLIW = 17, +++ MASK_SRLID = 16, +++ MASK_SRAIW = 17, +++ MASK_SRAID = 16, +++ MASK_ROTRIW = 17, +++ MASK_ROTRID = 16, +++ MASK_BSTR_W = 11, +++ MASK_BSTR_D = 9, +++ MASK_LDDIR = 14, +++ MASK_JUMP = 2, +++ MASK_ST = 8, +++ MASK_RDTIMELW = 22, +++ MASK_RDTIMEHW = 22, +++ MASK_RDTIMED = 22, +++ MASK_FLOAT_ARITH = 8, +++ MASK_FLOAT_MUL = 6, +++ MASK_FLDS = 10, +++ MASK_FLDD = 10, +++ MASK_FLDXS = 16, +++ MASK_FLDXD = 16, +++ MASK_SIGNED_AM = 12, +++ MASK_UNSIGNED_AM = 15, +++ MASK_COND_FLD = 15, +++ MASK_COND_LD = 14, +++ MASK_COND_FST = 15, +++ MASK_COND_ST = 14, +++ MASK_CACOP = 10, +++ MASK_TLBCLR = 32, +++ MASK_TLBFLUSH = 32, +++ MASK_TLBWR = 32, +++ MASK_TLBFILL = 32, +++ MASK_INVTLB = 17, +++ MASK_IDLE = 17, +++ MASK_PRELD = 11, +++ MASK_PRELDX = 17, +++ MASK_DBAR = 17, +++ MASK_IBAR = 17, +++ MASK_FCMPCONDS = 12, +++ MASK_FCMPCONDD = 12, +++ MASK_SYSCALL = 17, +++}; +++ +++#define is_ins(insval,mask,funccode) (((insval) & (insmask(mask))) == funccode) +++ +++#define is_data_process_ins(insval) \ +++ ((is_ins(insval,MASK_ARITH_IMM,INS_ARITH_IMM)) || \ +++ (is_ins(insval,MASK_ARITH,INS_ARITH)) || \ +++ (is_ins(insval,MASK_SHIFT,INS_SHIFT)) || \ +++ (is_ins(insval,MASK_LLW,INS_LLW)) || \ +++ (is_ins(insval,MASK_LLD,INS_LLD)) || \ +++ (is_ins(insval,MASK_LDPTRW,INS_LDPTRW)) || \ +++ (is_ins(insval,MASK_LDPTRD,INS_LDPTRD)) || \ +++ (is_ins(insval,MASK_LD,INS_LD)) || \ +++ (is_ins(insval,MASK_LDBU,INS_LDBU)) || \ +++ (is_ins(insval,MASK_LDHU,INS_LDHU)) || \ +++ (is_ins(insval,MASK_LDWU,INS_LDWU)) || \ +++ (is_ins(insval,MASK_LDXB,INS_LDXB)) || \ +++ (is_ins(insval,MASK_LDXH,INS_LDXH)) || \ +++ (is_ins(insval,MASK_LDXW,INS_LDXW)) || \ +++ (is_ins(insval,MASK_LDXD,INS_LDXD)) || \ +++ (is_ins(insval,MASK_CLOZ_W,INS_CLOZ_W)) || \ +++ (is_ins(insval,MASK_CLOZ_D,INS_CLOZ_D)) || \ +++ (is_ins(insval,MASK_REVB,INS_REVB)) || \ +++ (is_ins(insval,MASK_REVH,INS_REVH)) || \ +++ (is_ins(insval,MASK_BITREVB,INS_BITREVB)) || \ +++ (is_ins(insval,MASK_BITREVWD,INS_BITREVWD)) || \ +++ (is_ins(insval,MASK_EXT,INS_EXT)) || \ +++ (is_ins(insval,MASK_CPUCFG,INS_CPUCFG)) || \ +++ (is_ins(insval,MASK_ALSLW,INS_ALSLW)) || \ +++ (is_ins(insval,MASK_ALSLD,INS_ALSLD)) || \ +++ (is_ins(insval,MASK_BYTEPICK,INS_BYTEPICK)) || \ +++ (is_ins(insval,MASK_DIV_MOD,INS_DIV_MOD)) || \ +++ (is_ins(insval,MASK_BSTR_D,INS_BSTR_D)) || \ +++ (is_ins(insval,MASK_LDDIR,INS_LDDIR)) || \ +++ (is_ins(insval,MASK_ARITH_IMM_2,INS_ARITH_IMM_2)) || \ +++ (is_ins(insval,MASK_MOVFR2GRS,INS_MOVFR2GRS)) || \ +++ (is_ins(insval,MASK_MOVFR2GRD,INS_MOVFR2GRD)) || \ +++ (is_ins(insval,MASK_MOVFRH2GRS,INS_MOVFRH2GRS)) || \ +++ (is_ins(insval,MASK_MOVFCSR2GR,INS_MOVFCSR2GR)) || \ +++ (is_ins(insval,MASK_MOVCF2GR,INS_MOVCF2GR))) +++ +++#define is_jump_ins(insval) (is_ins(insval,MASK_JUMP,INS_JUMP)) +++ +++#define is_read_time_ins(insval) \ +++ ((is_ins(insval,MASK_RDTIMELW,INS_RDTIMELW)) || \ +++ (is_ins(insval,MASK_RDTIMEHW,INS_RDTIMEHW)) || \ +++ (is_ins(insval,MASK_RDTIMED,INS_RDTIMED))) +++ +++#define is_float_ins(insval) \ +++ ((is_ins(insval,MASK_FLOAT_ARITH,INS_FLOAT_ARITH)) || \ +++ (is_ins(insval,MASK_FLOAT_MUL,INS_FLOAT_MUL)) || \ +++ (is_ins(insval,MASK_FLDS,INS_FLDS)) || \ +++ (is_ins(insval,MASK_FLDD,INS_FLDD)) || \ +++ (is_ins(insval,MASK_FLDXS,INS_FLDXS)) || \ +++ (is_ins(insval,MASK_FLDXD,INS_FLDXD))) +++ +++#define is_nop_ins(insval) \ +++ ((is_ins(insval,MASK_CACOP,INS_CACOP)) || \ +++ (is_ins(insval,MASK_TLBCLR,INS_TLBCLR)) || \ +++ (is_ins(insval,MASK_TLBFLUSH,INS_TLBFLUSH)) || \ +++ (is_ins(insval,MASK_TLBWR,INS_TLBWR)) || \ +++ (is_ins(insval,MASK_TLBFILL,INS_TLBFILL)) || \ +++ (is_ins(insval,MASK_INVTLB,INS_INVTLB)) || \ +++ (is_ins(insval,MASK_IDLE,INS_IDLE)) || \ +++ (is_ins(insval,MASK_PRELD,INS_PRELD)) || \ +++ (is_ins(insval,MASK_PRELDX,INS_PRELDX)) || \ +++ (is_ins(insval,MASK_DBAR,INS_DBAR)) || \ +++ (is_ins(insval,MASK_IBAR,INS_IBAR)) || \ +++ (is_ins(insval,MASK_FCMPCONDS,INS_FCMPCONDS)) || \ +++ (is_ins(insval,MASK_FCMPCONDD,INS_FCMPCONDD)) || \ +++ (is_ins(insval,MASK_SYSCALL,INS_SYSCALL))) +++ +++ +++#define is_am_ins(insval) ((is_ins(insval,MASK_SIGNED_AM,INS_SIGNED_AM)) || (is_ins(insval,MASK_UNSIGNED_AM,INS_UNSIGNED_AM))) +++ +++#define is_cond_load_ins(insval) ((is_ins(insval,MASK_COND_FLD,INS_COND_FLD)) || (is_ins(insval,MASK_COND_LD,INS_COND_LD))) +++ +++#define is_cond_store_ins(insval) ((is_ins(insval,MASK_COND_FST,INS_COND_FST)) || (is_ins(insval,MASK_COND_ST,INS_COND_ST))) +++ +++#define is_cf_ins(insval) ((is_ins(insval,MASK_MOVFR2CF,INS_MOVFR2CF)) || (is_ins(insval,MASK_MOVGR2CF,INS_MOVGR2CF))) +++ +++#define is_stb_ins(insval) (is_ins(insval,MASK_STB,INS_STB)) +++#define is_sth_ins(insval) (is_ins(insval,MASK_STH,INS_STH)) +++#define is_stw_ins(insval) (is_ins(insval,MASK_STW,INS_STW)) +++#define is_std_ins(insval) (is_ins(insval,MASK_STD,INS_STD)) +++#define is_stptrw_ins(insval) (is_ins(insval,MASK_STPTRW,INS_STPTRW)) +++#define is_stptrd_ins(insval) (is_ins(insval,MASK_STPTRD,INS_STPTRD)) +++#define is_scw_ins(insval) (is_ins(insval,MASK_SCW,INS_SCW)) +++#define is_scd_ins(insval) (is_ins(insval,MASK_SCD,INS_SCD)) +++#define is_fsts_ins(insval) (is_ins(insval,MASK_FSTS,INS_FSTS)) +++#define is_fstd_ins(insval) (is_ins(insval,MASK_FSTD,INS_FSTD)) +++#define is_fstxs_ins(insval) (is_ins(insval,MASK_FSTXS,INS_FSTXS)) +++#define is_fstxd_ins(insval) (is_ins(insval,MASK_FSTXD,INS_FSTXD)) +++#define is_stxb_ins(insval) (is_ins(insval,MASK_STXB,INS_STXB)) +++#define is_stxh_ins(insval) (is_ins(insval,MASK_STXH,INS_STXH)) +++#define is_stxw_ins(insval) (is_ins(insval,MASK_STXW,INS_STXW)) +++#define is_stxd_ins(insval) (is_ins(insval,MASK_STXD,INS_STXD)) +++#define is_movgr2fcsr_ins(insval) (is_ins(insval,MASK_MOVGR2FCSR,INS_MOVGR2FCSR)) +++#define is_jirl_ins(insval) (is_ins(insval,MASK_JIRL,INS_JIRL)) +++#define is_bl_ins(insval) (is_ins(insval,MASK_BL,INS_BL)) +++#define is_ldgt_ins(insval) (is_ins(insval,MASK_LDGT,INS_LDGT)) +++#define is_ldle_ins(insval) (is_ins(insval,MASK_LDLE,INS_LDLE)) +++#define is_fldgt_ins(insval) (is_ins(insval,MASK_FLDGT,INS_FLDGT)) +++#define is_fldle_ins(insval) (is_ins(insval,MASK_FLDLE,INS_FLDLE)) +++#define is_stgt_ins(insval) (is_ins(insval,MASK_STGT,INS_STGT)) +++#define is_stle_ins(insval) (is_ins(insval,MASK_STLE,INS_STLE)) +++#define is_fstgt_ins(insval) (is_ins(insval,MASK_FSTGT,INS_FSTGT)) +++#define is_fstle_ins(insval) (is_ins(insval,MASK_FSTLE,INS_FSTLE)) +++ +++#define is_store_ins(insval) \ +++ ((is_stb_ins(insval)) || \ +++ (is_sth_ins(insval)) || \ +++ (is_stw_ins(insval)) || \ +++ (is_std_ins(insval)) || \ +++ (is_stptrw_ins(insval)) || \ +++ (is_stptrd_ins(insval)) || \ +++ (is_scw_ins(insval)) || \ +++ (is_scd_ins(insval)) || \ +++ (is_fsts_ins(insval)) || \ +++ (is_fstd_ins(insval)) || \ +++ (is_stxb_ins(insval)) || \ +++ (is_stxh_ins(insval)) || \ +++ (is_stxw_ins(insval)) || \ +++ (is_stxd_ins(insval))) +++ +++ +++ +++#endif /* ARCH_LOONGARCH_INSN_H */ +++ ++diff --git gdb-10.2/gdb/arch/loongarch-linux-nat.c gdb-10.2/gdb/arch/loongarch-linux-nat.c ++new file mode 100644 ++index 0000000..70bf742 ++--- /dev/null +++++ gdb-10.2/gdb/arch/loongarch-linux-nat.c ++@@ -0,0 +1,94 @@ +++/* Copyright (C) 2021 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 . */ +++ +++/* For external ptrace. */ +++#ifdef GDBSERVER +++#include "server.h" +++#include "nat/gdb_ptrace.h" +++#else +++#include "defs.h" +++#include "nat/gdb_ptrace.h" +++#endif +++ +++#include "arch/loongarch.h" +++#include "arch/loongarch-linux-nat.h" +++#include "loongarch-linux-tdep.h" +++#include "elf/common.h" +++#include +++ +++static uint32_t +++loongarch_cpucfg_may_ptrace (uint64_t rj, int tid) +++{ +++ char t_buf[rj * 4 + 4]; +++ struct iovec iovec = { .iov_base = &t_buf, .iov_len = sizeof (t_buf) }; +++ if (ptrace (PTRACE_GETREGSET, tid, NT_LARCH_CPUCFG, &iovec) < 0) +++ ((uint32_t *) t_buf)[rj] = loongarch_cpucfg (rj); +++ return ((uint32_t *) t_buf)[rj]; +++} +++ +++struct target_desc * +++loongarch_linux_read_description_runtime (int tid) +++{ +++ int rlen, fpu32, fpu64, lbt, lsx, lasx; +++ +++ uint32_t cpucfg1 = loongarch_cpucfg_may_ptrace (1, tid); +++ rlen = cpucfg1 & 0x2 /* LA64 */ ? 64 : 32; +++ +++ uint32_t cpucfg2 = loongarch_cpucfg_may_ptrace (2, tid); +++ fpu32 = 0, fpu64 = 0; +++ if (cpucfg2 & 0x4 /* FP_DP */) +++ fpu64 = 1; +++ else if (cpucfg2 & 0x2 /* FP_SP */) +++ fpu32 = 1; +++ if (fpu32 || fpu64) +++ { +++ loongarch_elf_fpregset_t regset; +++ struct iovec iovec = { .iov_base = ®set, .iov_len = sizeof (regset) }; +++ if (ptrace (PTRACE_GETREGSET, tid, NT_FPREGSET, &iovec) < 0) +++ fpu32 = 0, fpu64 = 0; +++ } +++ +++ lbt = 0; +++ if (cpucfg2 & 0x1c0000 /* LBT_X86 || LBT_ARM || LBT_MIPS */) +++ { +++ loongarch_elf_lbtregset_t regset; +++ struct iovec iovec = { .iov_base = ®set, .iov_len = sizeof (regset) }; +++ if (ptrace (PTRACE_GETREGSET, tid, NT_LARCH_LBT, &iovec) == 0) +++ lbt = 1; +++ } +++ +++ lsx = 0; +++ if (cpucfg2 & 0x40 /* LSX */) +++ { +++ loongarch_elf_lsxregset_t regset; +++ struct iovec iovec = { .iov_base = ®set, .iov_len = sizeof (regset) }; +++ if (ptrace (PTRACE_GETREGSET, tid, NT_LARCH_LSX, &iovec) == 0) +++ lsx = 1; +++ } +++ +++ lasx = 0; +++ if (cpucfg2 & 0x80 /* LASX */) +++ { +++ loongarch_elf_lasxregset_t regset; +++ struct iovec iovec = { .iov_base = ®set, .iov_len = sizeof (regset) }; +++ if (ptrace (PTRACE_GETREGSET, tid, NT_LARCH_LASX, &iovec) == 0) +++ lasx = 1; +++ } +++ +++ return loongarch_create_target_description (rlen, fpu32, fpu64, lbt, lsx, +++ lasx); +++} ++diff --git gdb-10.2/gdb/arch/loongarch-linux-nat.h gdb-10.2/gdb/arch/loongarch-linux-nat.h ++new file mode 100644 ++index 0000000..a9cd453 ++--- /dev/null +++++ gdb-10.2/gdb/arch/loongarch-linux-nat.h ++@@ -0,0 +1,35 @@ +++/* +++ Copyright (C) 2021 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 . */ +++ +++#ifndef LOONGARCH_LINUX_NAT_H +++#define LOONGARCH_LINUX_NAT_H +++#include +++ +++static inline uint32_t +++loongarch_cpucfg (uint64_t rj) +++{ +++ uint32_t ret; +++ asm ("cpucfg %0,%1" : "=r"(ret) : "r"(rj)); +++ return ret; +++} +++ +++struct target_desc; +++ +++extern struct target_desc *loongarch_linux_read_description_runtime (int tid); +++ +++#endif ++diff --git gdb-10.2/gdb/arch/loongarch.c gdb-10.2/gdb/arch/loongarch.c ++new file mode 100644 ++index 0000000..5a58647 ++--- /dev/null +++++ gdb-10.2/gdb/arch/loongarch.c ++@@ -0,0 +1,66 @@ +++#include "gdbsupport/common-defs.h" +++#include "gdbsupport/common-regcache.h" +++#include "arch/loongarch.h" +++ +++const char *loongarch_expedite_regs[] = {"r3", "pc", NULL}; +++ +++unsigned int loongarch_debug = 0; +++ +++#include <../features/loongarch/base32.c> +++#include <../features/loongarch/base64.c> +++#include <../features/loongarch/fpu32.c> +++#include <../features/loongarch/fpu64.c> +++#include <../features/loongarch/lbt32.c> +++#include <../features/loongarch/lbt64.c> +++#include <../features/loongarch/lsx.c> +++#include <../features/loongarch/lasx.c> +++ +++struct target_desc * +++loongarch_create_target_description (int rlen, int fpu32, int fpu64, int lbt, +++ int lsx, int lasx) +++{ +++ gdb_assert (rlen == 32 || rlen == 64); +++ +++ struct target_desc *tdesc = allocate_target_description (); +++ +++ set_tdesc_architecture (tdesc, rlen == 64 ? "loongarch64" : "loongarch32"); +++ +++ int regnum = 0; +++ +++ if (rlen == 64) +++ regnum = create_feature_loongarch_base64 (tdesc, regnum); +++ else if (rlen == 32) +++ regnum = create_feature_loongarch_base32 (tdesc, regnum); +++ else +++ gdb_assert_not_reached ("rlen unknown"); +++ +++ if (fpu32) +++ regnum = create_feature_loongarch_fpu32 (tdesc, regnum); +++ else if (fpu64) +++ regnum = create_feature_loongarch_fpu64 (tdesc, regnum); +++ +++ if (lbt && rlen == 32) +++ regnum = create_feature_loongarch_lbt32 (tdesc, regnum); +++ else if (lbt && rlen == 64) +++ regnum = create_feature_loongarch_lbt64 (tdesc, regnum); +++ +++ if (lsx) +++ regnum = create_feature_loongarch_lsx (tdesc, regnum); +++ +++ if (lasx) +++ regnum = create_feature_loongarch_lasx (tdesc, regnum); +++ +++ return tdesc; +++} +++ +++struct target_desc * +++loongarch_get_base_target_description (int rlen) +++{ +++ if (rlen == 64) +++ return loongarch_create_target_description (64, 0, 0, 0, 0, 0); +++ else if (rlen == 32) +++ return loongarch_create_target_description (32, 0, 0, 0, 0, 0); +++ else +++ gdb_assert_not_reached ("rlen unknown"); +++ return NULL; +++} ++diff --git gdb-10.2/gdb/arch/loongarch.h gdb-10.2/gdb/arch/loongarch.h ++new file mode 100644 ++index 0000000..9466232 ++--- /dev/null +++++ gdb-10.2/gdb/arch/loongarch.h ++@@ -0,0 +1,24 @@ +++#ifndef GDB_LOONGARCH_ARCH_H +++#define GDB_LOONGARCH_ARCH_H +++ +++#include "elf/loongarch.h" +++#include "opcode/loongarch.h" +++ +++extern unsigned int loongarch_debug; +++ +++struct target_desc; +++ +++extern const char *loongarch_expedite_regs[]; +++ +++extern struct target_desc * +++loongarch_get_base_target_description (int rlen); +++ +++extern struct target_desc * +++loongarch_create_target_description (int rlen, +++ int fpu32, +++ int fpu64, +++ int lbt, +++ int lsx, +++ int lasx); +++ +++#endif ++diff --git gdb-10.2/gdb/configure.host gdb-10.2/gdb/configure.host ++index ce52823..33a7f59 100644 ++--- gdb-10.2/gdb/configure.host +++++ gdb-10.2/gdb/configure.host ++@@ -63,6 +63,7 @@ alpha*) gdb_host_cpu=alpha ;; ++ arm*) gdb_host_cpu=arm ;; ++ hppa*) gdb_host_cpu=pa ;; ++ i[34567]86*) gdb_host_cpu=i386 ;; +++loongarch*) gdb_host_cpu=loongarch ;; ++ m68*) gdb_host_cpu=m68k ;; ++ mips*) gdb_host_cpu=mips ;; ++ powerpc* | rs6000) gdb_host_cpu=powerpc ;; ++@@ -120,6 +121,8 @@ i[34567]86-*-cygwin*) gdb_host=cygwin ;; ++ ++ ia64-*-linux*) gdb_host=linux ;; ++ +++loongarch*-linux*) gdb_host=linux ;; +++ ++ m68*-*-linux*) gdb_host=linux ;; ++ m68*-*-netbsdelf* | m68*-*-knetbsd*-gnu) ++ gdb_host=nbsdelf ;; ++diff --git gdb-10.2/gdb/configure.nat gdb-10.2/gdb/configure.nat ++index bb70e30..50d6539 100644 ++--- gdb-10.2/gdb/configure.nat +++++ gdb-10.2/gdb/configure.nat ++@@ -253,6 +253,10 @@ case ${gdb_host} in ++ # Host: Intel IA-64 running GNU/Linux ++ NATDEPFILES="${NATDEPFILES} ia64-linux-nat.o" ++ ;; +++ loongarch) +++ # Host: LoongArch, running GNU/Linux. +++ NATDEPFILES="${NATDEPFILES} loongarch-linux-nat.o arch/loongarch-linux-nat.o linux-nat-trad.o nat/loongarch-linux-watch.o" +++ ;; ++ m32r) ++ # Host: M32R based machine running GNU/Linux ++ NATDEPFILES="${NATDEPFILES} m32r-linux-nat.o" ++diff --git gdb-10.2/gdb/configure.tgt gdb-10.2/gdb/configure.tgt ++index a3e11c4..2d0cfe0 100644 ++--- gdb-10.2/gdb/configure.tgt +++++ gdb-10.2/gdb/configure.tgt ++@@ -95,6 +95,9 @@ xtensa*) ++ cpu_obs="xtensa-tdep.o xtensa-config.o solib-svr4.o" ++ ;; ++ +++loongarch*) +++ cpu_obs="arch/loongarch.o";; +++ ++ esac ++ ++ # 2. Get the objects per os in $TARG. ++@@ -346,6 +349,11 @@ lm32-*-*) ++ gdb_sim=../sim/lm32/libsim.a ++ ;; ++ +++loongarch*-linux*) +++ gdb_target_obs="loongarch-tdep.o loongarch-linux-tdep.o glibc-tdep.o linux-tdep.o solib-svr4.o symfile-mem.o" +++ build_gdbserver=yes +++ ;; +++ ++ m32c-*-*) ++ # Target: Renesas M32C family ++ gdb_target_obs="m32c-tdep.o" ++diff --git gdb-10.2/gdb/doc/gdb.texinfo gdb-10.2/gdb/doc/gdb.texinfo ++index 097aacd..94a8537 100644 ++--- gdb-10.2/gdb/doc/gdb.texinfo +++++ gdb-10.2/gdb/doc/gdb.texinfo ++@@ -45227,6 +45227,7 @@ registers using the capitalization used in the description. ++ * ARC Features:: ++ * ARM Features:: ++ * i386 Features:: +++* LoongArch Features:: ++ * MicroBlaze Features:: ++ * MIPS Features:: ++ * M68K Features:: ++@@ -45444,6 +45445,15 @@ The @samp{org.gnu.gdb.i386.pkeys} feature is optional. It should ++ describe a single register, @samp{pkru}. It is a 32-bit register ++ valid for i386 and amd64. ++ +++@node LoongArch Features +++@subsection LoongArch Features +++@cindex target descriptions, LoongArch Features +++ +++The @samp{org.gnu.gdb.loongarch.base} feature is required for LoongArch +++targets. It should contain the registers @samp{r0} through @samp{r31}, +++@samp{pc}, and @samp{badvaddr}. Either the architectural names (@samp{r0}, +++@samp{r1}, etc) can be used, or the ABI names (@samp{zero}, @samp{ra}, etc). +++ ++ @node MicroBlaze Features ++ @subsection MicroBlaze Features ++ @cindex target descriptions, MicroBlaze features ++diff --git gdb-10.2/gdb/features/Makefile gdb-10.2/gdb/features/Makefile ++index 67c3ae1..5d2c902 100644 ++--- gdb-10.2/gdb/features/Makefile +++++ gdb-10.2/gdb/features/Makefile ++@@ -74,6 +74,7 @@ arm-expedite = r11,sp,pc ++ i386-expedite = ebp,esp,eip ++ amd64-expedite = rbp,rsp,rip ++ x32-expedite = rbp,rsp,rip +++loongarch-expedite = r3,pc ++ mips-expedite = r29,pc ++ mips-dsp-expedite = r29,pc ++ mips64-expedite = r29,pc ++@@ -178,6 +179,7 @@ GDB = false ++ aarch64-feature = 1 ++ arm-feature = 1 ++ i386-feature = 1 +++loongarch-feature = 1 ++ riscv-feature = 1 ++ tic6x-feature = 1 ++ ++@@ -228,6 +230,14 @@ FEATURE_XMLFILES = aarch64-core.xml \ ++ i386/64bit-pkeys.xml \ ++ i386/64bit-sse.xml \ ++ i386/x32-core.xml \ +++ loongarch/base32.xml \ +++ loongarch/base64.xml \ +++ loongarch/fpu32.xml \ +++ loongarch/fpu64.xml \ +++ oongarch/lbt32.xml \ +++ oongarch/lbt64.xml \ +++ oongarch/lsx.xml \ +++ oongarch/lasx.xml \ ++ riscv/32bit-cpu.xml \ ++ riscv/32bit-fpu.xml \ ++ riscv/64bit-cpu.xml \ ++diff --git gdb-10.2/gdb/features/loongarch/base32.c gdb-10.2/gdb/features/loongarch/base32.c ++new file mode 100644 ++index 0000000..b6f2d06 ++--- /dev/null +++++ gdb-10.2/gdb/features/loongarch/base32.c ++@@ -0,0 +1,47 @@ +++/* THIS FILE IS GENERATED. -*- buffer-read-only: t -*- vi:set ro: +++ Original: base32.xml */ +++ +++#include "gdbsupport/tdesc.h" +++ +++static int +++create_feature_loongarch_base32 (struct target_desc *result, long regnum) +++{ +++ struct tdesc_feature *feature; +++ +++ feature = tdesc_create_feature (result, "org.gnu.gdb.loongarch.base"); +++ tdesc_create_reg (feature, "r0", regnum++, 1, "general", 32, "uint32"); +++ tdesc_create_reg (feature, "r1", regnum++, 1, "general", 32, "code_ptr"); +++ tdesc_create_reg (feature, "r2", regnum++, 1, "general", 32, "data_ptr"); +++ tdesc_create_reg (feature, "r3", regnum++, 1, "general", 32, "data_ptr"); +++ tdesc_create_reg (feature, "r4", regnum++, 1, "general", 32, "uint32"); +++ tdesc_create_reg (feature, "r5", regnum++, 1, "general", 32, "uint32"); +++ tdesc_create_reg (feature, "r6", regnum++, 1, "general", 32, "uint32"); +++ tdesc_create_reg (feature, "r7", regnum++, 1, "general", 32, "uint32"); +++ tdesc_create_reg (feature, "r8", regnum++, 1, "general", 32, "uint32"); +++ tdesc_create_reg (feature, "r9", regnum++, 1, "general", 32, "uint32"); +++ tdesc_create_reg (feature, "r10", regnum++, 1, "general", 32, "uint32"); +++ tdesc_create_reg (feature, "r11", regnum++, 1, "general", 32, "uint32"); +++ tdesc_create_reg (feature, "r12", regnum++, 1, "general", 32, "uint32"); +++ tdesc_create_reg (feature, "r13", regnum++, 1, "general", 32, "uint32"); +++ tdesc_create_reg (feature, "r14", regnum++, 1, "general", 32, "uint32"); +++ tdesc_create_reg (feature, "r15", regnum++, 1, "general", 32, "uint32"); +++ tdesc_create_reg (feature, "r16", regnum++, 1, "general", 32, "uint32"); +++ tdesc_create_reg (feature, "r17", regnum++, 1, "general", 32, "uint32"); +++ tdesc_create_reg (feature, "r18", regnum++, 1, "general", 32, "uint32"); +++ tdesc_create_reg (feature, "r19", regnum++, 1, "general", 32, "uint32"); +++ tdesc_create_reg (feature, "r20", regnum++, 1, "general", 32, "uint32"); +++ tdesc_create_reg (feature, "r21", regnum++, 1, "general", 32, "uint32"); +++ tdesc_create_reg (feature, "r22", regnum++, 1, "general", 32, "data_ptr"); +++ tdesc_create_reg (feature, "r23", regnum++, 1, "general", 32, "uint32"); +++ tdesc_create_reg (feature, "r24", regnum++, 1, "general", 32, "uint32"); +++ tdesc_create_reg (feature, "r25", regnum++, 1, "general", 32, "uint32"); +++ tdesc_create_reg (feature, "r26", regnum++, 1, "general", 32, "uint32"); +++ tdesc_create_reg (feature, "r27", regnum++, 1, "general", 32, "uint32"); +++ tdesc_create_reg (feature, "r28", regnum++, 1, "general", 32, "uint32"); +++ tdesc_create_reg (feature, "r29", regnum++, 1, "general", 32, "uint32"); +++ tdesc_create_reg (feature, "r30", regnum++, 1, "general", 32, "uint32"); +++ tdesc_create_reg (feature, "r31", regnum++, 1, "general", 32, "uint32"); +++ tdesc_create_reg (feature, "pc", regnum++, 1, "general", 32, "code_ptr"); +++ tdesc_create_reg (feature, "badvaddr", regnum++, 1, "general", 32, "code_ptr"); +++ return regnum; +++} ++diff --git gdb-10.2/gdb/features/loongarch/base32.xml gdb-10.2/gdb/features/loongarch/base32.xml ++new file mode 100644 ++index 0000000..0afe81b ++--- /dev/null +++++ gdb-10.2/gdb/features/loongarch/base32.xml ++@@ -0,0 +1,45 @@ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ ++diff --git gdb-10.2/gdb/features/loongarch/base64.c gdb-10.2/gdb/features/loongarch/base64.c ++new file mode 100644 ++index 0000000..3ee2d9a ++--- /dev/null +++++ gdb-10.2/gdb/features/loongarch/base64.c ++@@ -0,0 +1,47 @@ +++/* THIS FILE IS GENERATED. -*- buffer-read-only: t -*- vi:set ro: +++ Original: base64.xml */ +++ +++#include "gdbsupport/tdesc.h" +++ +++static int +++create_feature_loongarch_base64 (struct target_desc *result, long regnum) +++{ +++ struct tdesc_feature *feature; +++ +++ feature = tdesc_create_feature (result, "org.gnu.gdb.loongarch.base"); +++ tdesc_create_reg (feature, "r0", regnum++, 1, "general", 64, "uint64"); +++ tdesc_create_reg (feature, "r1", regnum++, 1, "general", 64, "code_ptr"); +++ tdesc_create_reg (feature, "r2", regnum++, 1, "general", 64, "data_ptr"); +++ tdesc_create_reg (feature, "r3", regnum++, 1, "general", 64, "data_ptr"); +++ tdesc_create_reg (feature, "r4", regnum++, 1, "general", 64, "uint64"); +++ tdesc_create_reg (feature, "r5", regnum++, 1, "general", 64, "uint64"); +++ tdesc_create_reg (feature, "r6", regnum++, 1, "general", 64, "uint64"); +++ tdesc_create_reg (feature, "r7", regnum++, 1, "general", 64, "uint64"); +++ tdesc_create_reg (feature, "r8", regnum++, 1, "general", 64, "uint64"); +++ tdesc_create_reg (feature, "r9", regnum++, 1, "general", 64, "uint64"); +++ tdesc_create_reg (feature, "r10", regnum++, 1, "general", 64, "uint64"); +++ tdesc_create_reg (feature, "r11", regnum++, 1, "general", 64, "uint64"); +++ tdesc_create_reg (feature, "r12", regnum++, 1, "general", 64, "uint64"); +++ tdesc_create_reg (feature, "r13", regnum++, 1, "general", 64, "uint64"); +++ tdesc_create_reg (feature, "r14", regnum++, 1, "general", 64, "uint64"); +++ tdesc_create_reg (feature, "r15", regnum++, 1, "general", 64, "uint64"); +++ tdesc_create_reg (feature, "r16", regnum++, 1, "general", 64, "uint64"); +++ tdesc_create_reg (feature, "r17", regnum++, 1, "general", 64, "uint64"); +++ tdesc_create_reg (feature, "r18", regnum++, 1, "general", 64, "uint64"); +++ tdesc_create_reg (feature, "r19", regnum++, 1, "general", 64, "uint64"); +++ tdesc_create_reg (feature, "r20", regnum++, 1, "general", 64, "uint64"); +++ tdesc_create_reg (feature, "r21", regnum++, 1, "general", 64, "uint64"); +++ tdesc_create_reg (feature, "r22", regnum++, 1, "general", 64, "data_ptr"); +++ tdesc_create_reg (feature, "r23", regnum++, 1, "general", 64, "uint64"); +++ tdesc_create_reg (feature, "r24", regnum++, 1, "general", 64, "uint64"); +++ tdesc_create_reg (feature, "r25", regnum++, 1, "general", 64, "uint64"); +++ tdesc_create_reg (feature, "r26", regnum++, 1, "general", 64, "uint64"); +++ tdesc_create_reg (feature, "r27", regnum++, 1, "general", 64, "uint64"); +++ tdesc_create_reg (feature, "r28", regnum++, 1, "general", 64, "uint64"); +++ tdesc_create_reg (feature, "r29", regnum++, 1, "general", 64, "uint64"); +++ tdesc_create_reg (feature, "r30", regnum++, 1, "general", 64, "uint64"); +++ tdesc_create_reg (feature, "r31", regnum++, 1, "general", 64, "uint64"); +++ tdesc_create_reg (feature, "pc", regnum++, 1, "general", 64, "code_ptr"); +++ tdesc_create_reg (feature, "badvaddr", regnum++, 1, "general", 64, "code_ptr"); +++ return regnum; +++} ++diff --git gdb-10.2/gdb/features/loongarch/base64.xml gdb-10.2/gdb/features/loongarch/base64.xml ++new file mode 100644 ++index 0000000..b53479f ++--- /dev/null +++++ gdb-10.2/gdb/features/loongarch/base64.xml ++@@ -0,0 +1,45 @@ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ ++diff --git gdb-10.2/gdb/features/loongarch/fpu32.c gdb-10.2/gdb/features/loongarch/fpu32.c ++new file mode 100644 ++index 0000000..bf8964a ++--- /dev/null +++++ gdb-10.2/gdb/features/loongarch/fpu32.c ++@@ -0,0 +1,54 @@ +++/* THIS FILE IS GENERATED. -*- buffer-read-only: t -*- vi:set ro: +++ Original: fpu32.xml */ +++ +++#include "gdbsupport/tdesc.h" +++ +++static int +++create_feature_loongarch_fpu32 (struct target_desc *result, long regnum) +++{ +++ struct tdesc_feature *feature; +++ +++ feature = tdesc_create_feature (result, "org.gnu.gdb.loongarch.fpu"); +++ tdesc_create_reg (feature, "f0", regnum++, 1, "float", 32, "ieee_single"); +++ tdesc_create_reg (feature, "f1", regnum++, 1, "float", 32, "ieee_single"); +++ tdesc_create_reg (feature, "f2", regnum++, 1, "float", 32, "ieee_single"); +++ tdesc_create_reg (feature, "f3", regnum++, 1, "float", 32, "ieee_single"); +++ tdesc_create_reg (feature, "f4", regnum++, 1, "float", 32, "ieee_single"); +++ tdesc_create_reg (feature, "f5", regnum++, 1, "float", 32, "ieee_single"); +++ tdesc_create_reg (feature, "f6", regnum++, 1, "float", 32, "ieee_single"); +++ tdesc_create_reg (feature, "f7", regnum++, 1, "float", 32, "ieee_single"); +++ tdesc_create_reg (feature, "f8", regnum++, 1, "float", 32, "ieee_single"); +++ tdesc_create_reg (feature, "f9", regnum++, 1, "float", 32, "ieee_single"); +++ tdesc_create_reg (feature, "f10", regnum++, 1, "float", 32, "ieee_single"); +++ tdesc_create_reg (feature, "f11", regnum++, 1, "float", 32, "ieee_single"); +++ tdesc_create_reg (feature, "f12", regnum++, 1, "float", 32, "ieee_single"); +++ tdesc_create_reg (feature, "f13", regnum++, 1, "float", 32, "ieee_single"); +++ tdesc_create_reg (feature, "f14", regnum++, 1, "float", 32, "ieee_single"); +++ tdesc_create_reg (feature, "f15", regnum++, 1, "float", 32, "ieee_single"); +++ tdesc_create_reg (feature, "f16", regnum++, 1, "float", 32, "ieee_single"); +++ tdesc_create_reg (feature, "f17", regnum++, 1, "float", 32, "ieee_single"); +++ tdesc_create_reg (feature, "f18", regnum++, 1, "float", 32, "ieee_single"); +++ tdesc_create_reg (feature, "f19", regnum++, 1, "float", 32, "ieee_single"); +++ tdesc_create_reg (feature, "f20", regnum++, 1, "float", 32, "ieee_single"); +++ tdesc_create_reg (feature, "f21", regnum++, 1, "float", 32, "ieee_single"); +++ tdesc_create_reg (feature, "f22", regnum++, 1, "float", 32, "ieee_single"); +++ tdesc_create_reg (feature, "f23", regnum++, 1, "float", 32, "ieee_single"); +++ tdesc_create_reg (feature, "f24", regnum++, 1, "float", 32, "ieee_single"); +++ tdesc_create_reg (feature, "f25", regnum++, 1, "float", 32, "ieee_single"); +++ tdesc_create_reg (feature, "f26", regnum++, 1, "float", 32, "ieee_single"); +++ tdesc_create_reg (feature, "f27", regnum++, 1, "float", 32, "ieee_single"); +++ tdesc_create_reg (feature, "f28", regnum++, 1, "float", 32, "ieee_single"); +++ tdesc_create_reg (feature, "f29", regnum++, 1, "float", 32, "ieee_single"); +++ tdesc_create_reg (feature, "f30", regnum++, 1, "float", 32, "ieee_single"); +++ tdesc_create_reg (feature, "f31", regnum++, 1, "float", 32, "ieee_single"); +++ tdesc_create_reg (feature, "fcc0", regnum++, 1, "float", 8, "uint8"); +++ tdesc_create_reg (feature, "fcc1", regnum++, 1, "float", 8, "uint8"); +++ tdesc_create_reg (feature, "fcc2", regnum++, 1, "float", 8, "uint8"); +++ tdesc_create_reg (feature, "fcc3", regnum++, 1, "float", 8, "uint8"); +++ tdesc_create_reg (feature, "fcc4", regnum++, 1, "float", 8, "uint8"); +++ tdesc_create_reg (feature, "fcc5", regnum++, 1, "float", 8, "uint8"); +++ tdesc_create_reg (feature, "fcc6", regnum++, 1, "float", 8, "uint8"); +++ tdesc_create_reg (feature, "fcc7", regnum++, 1, "float", 8, "uint8"); +++ tdesc_create_reg (feature, "fcsr", regnum++, 1, "float", 32, "uint32"); +++ return regnum; +++} ++diff --git gdb-10.2/gdb/features/loongarch/fpu32.xml gdb-10.2/gdb/features/loongarch/fpu32.xml ++new file mode 100644 ++index 0000000..8421730 ++--- /dev/null +++++ gdb-10.2/gdb/features/loongarch/fpu32.xml ++@@ -0,0 +1,53 @@ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ ++diff --git gdb-10.2/gdb/features/loongarch/fpu64.c gdb-10.2/gdb/features/loongarch/fpu64.c ++new file mode 100644 ++index 0000000..f9e24c3 ++--- /dev/null +++++ gdb-10.2/gdb/features/loongarch/fpu64.c ++@@ -0,0 +1,62 @@ +++/* THIS FILE IS GENERATED. -*- buffer-read-only: t -*- vi:set ro: +++ Original: fpu64.xml */ +++ +++#include "gdbsupport/tdesc.h" +++ +++static int +++create_feature_loongarch_fpu64 (struct target_desc *result, long regnum) +++{ +++ struct tdesc_feature *feature; +++ +++ feature = tdesc_create_feature (result, "org.gnu.gdb.loongarch.fpu"); +++ tdesc_type_with_fields *type_with_fields; +++ type_with_fields = tdesc_create_union (feature, "fpu64type"); +++ tdesc_type *field_type; +++ field_type = tdesc_named_type (feature, "ieee_single"); +++ tdesc_add_field (type_with_fields, "f", field_type); +++ field_type = tdesc_named_type (feature, "ieee_double"); +++ tdesc_add_field (type_with_fields, "d", field_type); +++ +++ tdesc_create_reg (feature, "f0", regnum++, 1, "float", 64, "fpu64type"); +++ tdesc_create_reg (feature, "f1", regnum++, 1, "float", 64, "fpu64type"); +++ tdesc_create_reg (feature, "f2", regnum++, 1, "float", 64, "fpu64type"); +++ tdesc_create_reg (feature, "f3", regnum++, 1, "float", 64, "fpu64type"); +++ tdesc_create_reg (feature, "f4", regnum++, 1, "float", 64, "fpu64type"); +++ tdesc_create_reg (feature, "f5", regnum++, 1, "float", 64, "fpu64type"); +++ tdesc_create_reg (feature, "f6", regnum++, 1, "float", 64, "fpu64type"); +++ tdesc_create_reg (feature, "f7", regnum++, 1, "float", 64, "fpu64type"); +++ tdesc_create_reg (feature, "f8", regnum++, 1, "float", 64, "fpu64type"); +++ tdesc_create_reg (feature, "f9", regnum++, 1, "float", 64, "fpu64type"); +++ tdesc_create_reg (feature, "f10", regnum++, 1, "float", 64, "fpu64type"); +++ tdesc_create_reg (feature, "f11", regnum++, 1, "float", 64, "fpu64type"); +++ tdesc_create_reg (feature, "f12", regnum++, 1, "float", 64, "fpu64type"); +++ tdesc_create_reg (feature, "f13", regnum++, 1, "float", 64, "fpu64type"); +++ tdesc_create_reg (feature, "f14", regnum++, 1, "float", 64, "fpu64type"); +++ tdesc_create_reg (feature, "f15", regnum++, 1, "float", 64, "fpu64type"); +++ tdesc_create_reg (feature, "f16", regnum++, 1, "float", 64, "fpu64type"); +++ tdesc_create_reg (feature, "f17", regnum++, 1, "float", 64, "fpu64type"); +++ tdesc_create_reg (feature, "f18", regnum++, 1, "float", 64, "fpu64type"); +++ tdesc_create_reg (feature, "f19", regnum++, 1, "float", 64, "fpu64type"); +++ tdesc_create_reg (feature, "f20", regnum++, 1, "float", 64, "fpu64type"); +++ tdesc_create_reg (feature, "f21", regnum++, 1, "float", 64, "fpu64type"); +++ tdesc_create_reg (feature, "f22", regnum++, 1, "float", 64, "fpu64type"); +++ tdesc_create_reg (feature, "f23", regnum++, 1, "float", 64, "fpu64type"); +++ tdesc_create_reg (feature, "f24", regnum++, 1, "float", 64, "fpu64type"); +++ tdesc_create_reg (feature, "f25", regnum++, 1, "float", 64, "fpu64type"); +++ tdesc_create_reg (feature, "f26", regnum++, 1, "float", 64, "fpu64type"); +++ tdesc_create_reg (feature, "f27", regnum++, 1, "float", 64, "fpu64type"); +++ tdesc_create_reg (feature, "f28", regnum++, 1, "float", 64, "fpu64type"); +++ tdesc_create_reg (feature, "f29", regnum++, 1, "float", 64, "fpu64type"); +++ tdesc_create_reg (feature, "f30", regnum++, 1, "float", 64, "fpu64type"); +++ tdesc_create_reg (feature, "f31", regnum++, 1, "float", 64, "fpu64type"); +++ tdesc_create_reg (feature, "fcc0", regnum++, 1, "float", 8, "uint8"); +++ tdesc_create_reg (feature, "fcc1", regnum++, 1, "float", 8, "uint8"); +++ tdesc_create_reg (feature, "fcc2", regnum++, 1, "float", 8, "uint8"); +++ tdesc_create_reg (feature, "fcc3", regnum++, 1, "float", 8, "uint8"); +++ tdesc_create_reg (feature, "fcc4", regnum++, 1, "float", 8, "uint8"); +++ tdesc_create_reg (feature, "fcc5", regnum++, 1, "float", 8, "uint8"); +++ tdesc_create_reg (feature, "fcc6", regnum++, 1, "float", 8, "uint8"); +++ tdesc_create_reg (feature, "fcc7", regnum++, 1, "float", 8, "uint8"); +++ tdesc_create_reg (feature, "fcsr", regnum++, 1, "float", 32, "uint32"); +++ return regnum; +++} ++diff --git gdb-10.2/gdb/features/loongarch/fpu64.xml gdb-10.2/gdb/features/loongarch/fpu64.xml ++new file mode 100644 ++index 0000000..420be8b ++--- /dev/null +++++ gdb-10.2/gdb/features/loongarch/fpu64.xml ++@@ -0,0 +1,58 @@ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ ++diff --git gdb-10.2/gdb/features/loongarch/lasx.c gdb-10.2/gdb/features/loongarch/lasx.c ++new file mode 100644 ++index 0000000..96e3ea9 ++--- /dev/null +++++ gdb-10.2/gdb/features/loongarch/lasx.c ++@@ -0,0 +1,80 @@ +++/* THIS FILE IS GENERATED. -*- buffer-read-only: t -*- vi:set ro: +++ Original: lasx.xml */ +++ +++#include "gdbsupport/tdesc.h" +++ +++static int +++create_feature_loongarch_lasx (struct target_desc *result, long regnum) +++{ +++ struct tdesc_feature *feature; +++ +++ feature = tdesc_create_feature (result, "org.gnu.gdb.loongarch.lasx"); +++ tdesc_type *element_type; +++ element_type = tdesc_named_type (feature, "int8"); +++ tdesc_create_vector (feature, "v32i8", element_type, 32); +++ +++ element_type = tdesc_named_type (feature, "int16"); +++ tdesc_create_vector (feature, "v16i16", element_type, 16); +++ +++ element_type = tdesc_named_type (feature, "int32"); +++ tdesc_create_vector (feature, "v8i32", element_type, 8); +++ +++ element_type = tdesc_named_type (feature, "int64"); +++ tdesc_create_vector (feature, "v4i64", element_type, 4); +++ +++ element_type = tdesc_named_type (feature, "ieee_single"); +++ tdesc_create_vector (feature, "v8f32", element_type, 8); +++ +++ element_type = tdesc_named_type (feature, "ieee_double"); +++ tdesc_create_vector (feature, "v4f64", element_type, 4); +++ +++ tdesc_type_with_fields *type_with_fields; +++ type_with_fields = tdesc_create_union (feature, "lasxv"); +++ tdesc_type *field_type; +++ field_type = tdesc_named_type (feature, "v32i8"); +++ tdesc_add_field (type_with_fields, "v32i8", field_type); +++ field_type = tdesc_named_type (feature, "v16i16"); +++ tdesc_add_field (type_with_fields, "v16i16", field_type); +++ field_type = tdesc_named_type (feature, "v8i32"); +++ tdesc_add_field (type_with_fields, "v8i32", field_type); +++ field_type = tdesc_named_type (feature, "v4i64"); +++ tdesc_add_field (type_with_fields, "v4i64", field_type); +++ field_type = tdesc_named_type (feature, "v8f32"); +++ tdesc_add_field (type_with_fields, "v8f32", field_type); +++ field_type = tdesc_named_type (feature, "v4f64"); +++ tdesc_add_field (type_with_fields, "v4f64", field_type); +++ +++ tdesc_create_reg (feature, "xr0", regnum++, 1, "lasx", 256, "lasxv"); +++ tdesc_create_reg (feature, "xr1", regnum++, 1, "lasx", 256, "lasxv"); +++ tdesc_create_reg (feature, "xr2", regnum++, 1, "lasx", 256, "lasxv"); +++ tdesc_create_reg (feature, "xr3", regnum++, 1, "lasx", 256, "lasxv"); +++ tdesc_create_reg (feature, "xr4", regnum++, 1, "lasx", 256, "lasxv"); +++ tdesc_create_reg (feature, "xr5", regnum++, 1, "lasx", 256, "lasxv"); +++ tdesc_create_reg (feature, "xr6", regnum++, 1, "lasx", 256, "lasxv"); +++ tdesc_create_reg (feature, "xr7", regnum++, 1, "lasx", 256, "lasxv"); +++ tdesc_create_reg (feature, "xr8", regnum++, 1, "lasx", 256, "lasxv"); +++ tdesc_create_reg (feature, "xr9", regnum++, 1, "lasx", 256, "lasxv"); +++ tdesc_create_reg (feature, "xr10", regnum++, 1, "lasx", 256, "lasxv"); +++ tdesc_create_reg (feature, "xr11", regnum++, 1, "lasx", 256, "lasxv"); +++ tdesc_create_reg (feature, "xr12", regnum++, 1, "lasx", 256, "lasxv"); +++ tdesc_create_reg (feature, "xr13", regnum++, 1, "lasx", 256, "lasxv"); +++ tdesc_create_reg (feature, "xr14", regnum++, 1, "lasx", 256, "lasxv"); +++ tdesc_create_reg (feature, "xr15", regnum++, 1, "lasx", 256, "lasxv"); +++ tdesc_create_reg (feature, "xr16", regnum++, 1, "lasx", 256, "lasxv"); +++ tdesc_create_reg (feature, "xr17", regnum++, 1, "lasx", 256, "lasxv"); +++ tdesc_create_reg (feature, "xr18", regnum++, 1, "lasx", 256, "lasxv"); +++ tdesc_create_reg (feature, "xr19", regnum++, 1, "lasx", 256, "lasxv"); +++ tdesc_create_reg (feature, "xr20", regnum++, 1, "lasx", 256, "lasxv"); +++ tdesc_create_reg (feature, "xr21", regnum++, 1, "lasx", 256, "lasxv"); +++ tdesc_create_reg (feature, "xr22", regnum++, 1, "lasx", 256, "lasxv"); +++ tdesc_create_reg (feature, "xr23", regnum++, 1, "lasx", 256, "lasxv"); +++ tdesc_create_reg (feature, "xr24", regnum++, 1, "lasx", 256, "lasxv"); +++ tdesc_create_reg (feature, "xr25", regnum++, 1, "lasx", 256, "lasxv"); +++ tdesc_create_reg (feature, "xr26", regnum++, 1, "lasx", 256, "lasxv"); +++ tdesc_create_reg (feature, "xr27", regnum++, 1, "lasx", 256, "lasxv"); +++ tdesc_create_reg (feature, "xr28", regnum++, 1, "lasx", 256, "lasxv"); +++ tdesc_create_reg (feature, "xr29", regnum++, 1, "lasx", 256, "lasxv"); +++ tdesc_create_reg (feature, "xr30", regnum++, 1, "lasx", 256, "lasxv"); +++ tdesc_create_reg (feature, "xr31", regnum++, 1, "lasx", 256, "lasxv"); +++ return regnum; +++} ++diff --git gdb-10.2/gdb/features/loongarch/lasx.xml gdb-10.2/gdb/features/loongarch/lasx.xml ++new file mode 100644 ++index 0000000..6f73df0 ++--- /dev/null +++++ gdb-10.2/gdb/features/loongarch/lasx.xml ++@@ -0,0 +1,59 @@ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ ++diff --git gdb-10.2/gdb/features/loongarch/lbt32.c gdb-10.2/gdb/features/loongarch/lbt32.c ++new file mode 100644 ++index 0000000..d245c75 ++--- /dev/null +++++ gdb-10.2/gdb/features/loongarch/lbt32.c ++@@ -0,0 +1,19 @@ +++/* THIS FILE IS GENERATED. -*- buffer-read-only: t -*- vi:set ro: +++ Original: lbt32.xml */ +++ +++#include "gdbsupport/tdesc.h" +++ +++static int +++create_feature_loongarch_lbt32 (struct target_desc *result, long regnum) +++{ +++ struct tdesc_feature *feature; +++ +++ feature = tdesc_create_feature (result, "org.gnu.gdb.loongarch.lbt"); +++ tdesc_create_reg (feature, "scr0", regnum++, 1, "lbt", 32, "uint32"); +++ tdesc_create_reg (feature, "scr1", regnum++, 1, "lbt", 32, "uint32"); +++ tdesc_create_reg (feature, "scr2", regnum++, 1, "lbt", 32, "uint32"); +++ tdesc_create_reg (feature, "scr3", regnum++, 1, "lbt", 32, "uint32"); +++ tdesc_create_reg (feature, "EFLAG", regnum++, 1, "lbt", 32, "uint32"); +++ tdesc_create_reg (feature, "x86_top", regnum++, 1, "lbt", 8, "uint8"); +++ return regnum; +++} ++diff --git gdb-10.2/gdb/features/loongarch/lbt32.xml gdb-10.2/gdb/features/loongarch/lbt32.xml ++new file mode 100644 ++index 0000000..1c0133e ++--- /dev/null +++++ gdb-10.2/gdb/features/loongarch/lbt32.xml ++@@ -0,0 +1,17 @@ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ ++diff --git gdb-10.2/gdb/features/loongarch/lbt64.c gdb-10.2/gdb/features/loongarch/lbt64.c ++new file mode 100644 ++index 0000000..ecef330 ++--- /dev/null +++++ gdb-10.2/gdb/features/loongarch/lbt64.c ++@@ -0,0 +1,19 @@ +++/* THIS FILE IS GENERATED. -*- buffer-read-only: t -*- vi:set ro: +++ Original: lbt64.xml */ +++ +++#include "gdbsupport/tdesc.h" +++ +++static int +++create_feature_loongarch_lbt64 (struct target_desc *result, long regnum) +++{ +++ struct tdesc_feature *feature; +++ +++ feature = tdesc_create_feature (result, "org.gnu.gdb.loongarch.lbt"); +++ tdesc_create_reg (feature, "scr0", regnum++, 1, "lbt", 64, "uint64"); +++ tdesc_create_reg (feature, "scr1", regnum++, 1, "lbt", 64, "uint64"); +++ tdesc_create_reg (feature, "scr2", regnum++, 1, "lbt", 64, "uint64"); +++ tdesc_create_reg (feature, "scr3", regnum++, 1, "lbt", 64, "uint64"); +++ tdesc_create_reg (feature, "EFLAG", regnum++, 1, "lbt", 32, "uint32"); +++ tdesc_create_reg (feature, "x86_top", regnum++, 1, "lbt", 8, "uint8"); +++ return regnum; +++} ++diff --git gdb-10.2/gdb/features/loongarch/lbt64.xml gdb-10.2/gdb/features/loongarch/lbt64.xml ++new file mode 100644 ++index 0000000..1df26f5 ++--- /dev/null +++++ gdb-10.2/gdb/features/loongarch/lbt64.xml ++@@ -0,0 +1,17 @@ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ ++diff --git gdb-10.2/gdb/features/loongarch/lsx.c gdb-10.2/gdb/features/loongarch/lsx.c ++new file mode 100644 ++index 0000000..dd253f3 ++--- /dev/null +++++ gdb-10.2/gdb/features/loongarch/lsx.c ++@@ -0,0 +1,80 @@ +++/* THIS FILE IS GENERATED. -*- buffer-read-only: t -*- vi:set ro: +++ Original: lsx.xml */ +++ +++#include "gdbsupport/tdesc.h" +++ +++static int +++create_feature_loongarch_lsx (struct target_desc *result, long regnum) +++{ +++ struct tdesc_feature *feature; +++ +++ feature = tdesc_create_feature (result, "org.gnu.gdb.loongarch.lsx"); +++ tdesc_type *element_type; +++ element_type = tdesc_named_type (feature, "int8"); +++ tdesc_create_vector (feature, "v16i8", element_type, 16); +++ +++ element_type = tdesc_named_type (feature, "int16"); +++ tdesc_create_vector (feature, "v8i16", element_type, 8); +++ +++ element_type = tdesc_named_type (feature, "int32"); +++ tdesc_create_vector (feature, "v4i32", element_type, 4); +++ +++ element_type = tdesc_named_type (feature, "int64"); +++ tdesc_create_vector (feature, "v2i64", element_type, 2); +++ +++ element_type = tdesc_named_type (feature, "ieee_single"); +++ tdesc_create_vector (feature, "v4f32", element_type, 4); +++ +++ element_type = tdesc_named_type (feature, "ieee_double"); +++ tdesc_create_vector (feature, "v2f64", element_type, 2); +++ +++ tdesc_type_with_fields *type_with_fields; +++ type_with_fields = tdesc_create_union (feature, "lsxv"); +++ tdesc_type *field_type; +++ field_type = tdesc_named_type (feature, "v16i8"); +++ tdesc_add_field (type_with_fields, "v16i8", field_type); +++ field_type = tdesc_named_type (feature, "v8i16"); +++ tdesc_add_field (type_with_fields, "v8i16", field_type); +++ field_type = tdesc_named_type (feature, "v4i32"); +++ tdesc_add_field (type_with_fields, "v4i32", field_type); +++ field_type = tdesc_named_type (feature, "v2i64"); +++ tdesc_add_field (type_with_fields, "v2i64", field_type); +++ field_type = tdesc_named_type (feature, "v4f32"); +++ tdesc_add_field (type_with_fields, "v4f32", field_type); +++ field_type = tdesc_named_type (feature, "v2f64"); +++ tdesc_add_field (type_with_fields, "v2f64", field_type); +++ +++ tdesc_create_reg (feature, "vr0", regnum++, 1, "lsx", 128, "lsxv"); +++ tdesc_create_reg (feature, "vr1", regnum++, 1, "lsx", 128, "lsxv"); +++ tdesc_create_reg (feature, "vr2", regnum++, 1, "lsx", 128, "lsxv"); +++ tdesc_create_reg (feature, "vr3", regnum++, 1, "lsx", 128, "lsxv"); +++ tdesc_create_reg (feature, "vr4", regnum++, 1, "lsx", 128, "lsxv"); +++ tdesc_create_reg (feature, "vr5", regnum++, 1, "lsx", 128, "lsxv"); +++ tdesc_create_reg (feature, "vr6", regnum++, 1, "lsx", 128, "lsxv"); +++ tdesc_create_reg (feature, "vr7", regnum++, 1, "lsx", 128, "lsxv"); +++ tdesc_create_reg (feature, "vr8", regnum++, 1, "lsx", 128, "lsxv"); +++ tdesc_create_reg (feature, "vr9", regnum++, 1, "lsx", 128, "lsxv"); +++ tdesc_create_reg (feature, "vr10", regnum++, 1, "lsx", 128, "lsxv"); +++ tdesc_create_reg (feature, "vr11", regnum++, 1, "lsx", 128, "lsxv"); +++ tdesc_create_reg (feature, "vr12", regnum++, 1, "lsx", 128, "lsxv"); +++ tdesc_create_reg (feature, "vr13", regnum++, 1, "lsx", 128, "lsxv"); +++ tdesc_create_reg (feature, "vr14", regnum++, 1, "lsx", 128, "lsxv"); +++ tdesc_create_reg (feature, "vr15", regnum++, 1, "lsx", 128, "lsxv"); +++ tdesc_create_reg (feature, "vr16", regnum++, 1, "lsx", 128, "lsxv"); +++ tdesc_create_reg (feature, "vr17", regnum++, 1, "lsx", 128, "lsxv"); +++ tdesc_create_reg (feature, "vr18", regnum++, 1, "lsx", 128, "lsxv"); +++ tdesc_create_reg (feature, "vr19", regnum++, 1, "lsx", 128, "lsxv"); +++ tdesc_create_reg (feature, "vr20", regnum++, 1, "lsx", 128, "lsxv"); +++ tdesc_create_reg (feature, "vr21", regnum++, 1, "lsx", 128, "lsxv"); +++ tdesc_create_reg (feature, "vr22", regnum++, 1, "lsx", 128, "lsxv"); +++ tdesc_create_reg (feature, "vr23", regnum++, 1, "lsx", 128, "lsxv"); +++ tdesc_create_reg (feature, "vr24", regnum++, 1, "lsx", 128, "lsxv"); +++ tdesc_create_reg (feature, "vr25", regnum++, 1, "lsx", 128, "lsxv"); +++ tdesc_create_reg (feature, "vr26", regnum++, 1, "lsx", 128, "lsxv"); +++ tdesc_create_reg (feature, "vr27", regnum++, 1, "lsx", 128, "lsxv"); +++ tdesc_create_reg (feature, "vr28", regnum++, 1, "lsx", 128, "lsxv"); +++ tdesc_create_reg (feature, "vr29", regnum++, 1, "lsx", 128, "lsxv"); +++ tdesc_create_reg (feature, "vr30", regnum++, 1, "lsx", 128, "lsxv"); +++ tdesc_create_reg (feature, "vr31", regnum++, 1, "lsx", 128, "lsxv"); +++ return regnum; +++} ++diff --git gdb-10.2/gdb/features/loongarch/lsx.xml gdb-10.2/gdb/features/loongarch/lsx.xml ++new file mode 100644 ++index 0000000..a0a6ba4 ++--- /dev/null +++++ gdb-10.2/gdb/features/loongarch/lsx.xml ++@@ -0,0 +1,59 @@ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ ++diff --git gdb-10.2/gdb/loongarch-linux-nat.c gdb-10.2/gdb/loongarch-linux-nat.c ++new file mode 100644 ++index 0000000..72c57dc ++--- /dev/null +++++ gdb-10.2/gdb/loongarch-linux-nat.c ++@@ -0,0 +1,852 @@ +++#include "defs.h" +++#include "command.h" +++#include "gdbcmd.h" +++#include "inferior.h" +++#include "loongarch-tdep.h" +++#include "target.h" +++#include "regcache.h" +++#include "linux-nat-trad.h" +++#include "loongarch-linux-tdep.h" +++#include "target-descriptions.h" +++ +++#include "gdb_proc_service.h" +++#include "gregset.h" +++ +++#include "nat/gdb_ptrace.h" +++#include +++#include "inf-ptrace.h" +++#include "arch/loongarch-linux-nat.h" +++#include "elf/common.h" +++ +++#include "nat/loongarch-linux-watch.h" +++ +++class loongarch_linux_nat_target final : public linux_nat_trad_target +++{ +++public: +++ void fetch_registers (struct regcache *, int) override; +++ void store_registers (struct regcache *, int) override; +++ +++ void close () override; +++ +++ int can_use_hw_breakpoint (enum bptype, int, int) override; +++ +++ int insert_hw_breakpoint (struct gdbarch *, struct bp_target_info *) override; +++ +++ int remove_hw_breakpoint (struct gdbarch *, struct bp_target_info *) override; +++ +++ int remove_watchpoint (CORE_ADDR, int, enum target_hw_bp_type, +++ struct expression *) override; +++ +++ int insert_watchpoint (CORE_ADDR, int, enum target_hw_bp_type, +++ struct expression *) override; +++ +++ bool stopped_by_watchpoint () override; +++ +++ bool stopped_data_address (CORE_ADDR *) override; +++ +++ int region_ok_for_hw_watchpoint (CORE_ADDR, int) override; +++ +++ const struct target_desc *read_description () override; +++ +++ enum target_xfer_status xfer_partial (enum target_object object, +++ const char *annex, gdb_byte *readbuf, +++ const gdb_byte *writebuf, +++ ULONGEST offset, ULONGEST len, +++ ULONGEST *xfered_len) override; +++ +++protected: +++ CORE_ADDR register_u_offset (struct gdbarch *gdbarch, +++ int regno, int store_p) override; +++ +++ void low_new_thread (struct lwp_info *lp) override; +++ +++private: +++ void loongarch_fetch_regs (struct regcache *regcache, int regno); +++ void loongarch_store_regs (struct regcache *regcache, int regno); +++}; +++ +++/* Assume that we have PTRACE_{GET,SET}REGSET et al. support. If we do not, +++ we'll clear this and use PTRACE_PEEKUSR instead. +++ 问题的关键在于LA64可以跑32位程序和64位程序,如果一个32位GDB调试64位程序, +++ ptrace的各参数和返回值也是32位,无法拿到被调试程序的64位寄存器值。所以 +++ 我们尽量不使用PTRACE_{PEEK,POKE}USR。我们对PTRACE_{PEEK,POKE}USR的支持很 +++ 消极,在内核真的出问题或者是简单调试才使用PTRACE_{PEEK,POKE}USR。 */ +++extern enum tribool have_ptrace_getregset; +++ +++static void ensure_ptrace_getregset () +++{ +++ have_ptrace_getregset = TRIBOOL_TRUE; +++} +++ +++/* Fetch REGNO (or all registers if REGNO == -1) from the target +++ using any working method. */ +++ +++void +++loongarch_linux_nat_target::fetch_registers (struct regcache *regcache, int regnum) +++{ +++ if (have_ptrace_getregset == TRIBOOL_UNKNOWN) +++ ensure_ptrace_getregset (); +++ +++ if (sizeof (void *) == 4) +++ gdb_assert (have_ptrace_getregset == TRIBOOL_TRUE +++ || register_size (regcache->arch (), gdbarch_tdep (regcache->arch ())->regs.r) != 32); +++ +++ if (have_ptrace_getregset == TRIBOOL_TRUE) +++ loongarch_fetch_regs (regcache, regnum); +++ else +++ linux_nat_trad_target::fetch_registers (regcache, regnum); +++} +++ +++/* Store REGNO (or all registers if REGNO == -1) to the target +++ using any working method. */ +++ +++void +++loongarch_linux_nat_target::store_registers (struct regcache *regcache, int regnum) +++{ +++ if (have_ptrace_getregset == TRIBOOL_UNKNOWN) +++ ensure_ptrace_getregset (); +++ +++ if (sizeof (void *) == 4) +++ gdb_assert (have_ptrace_getregset == TRIBOOL_TRUE +++ || register_size (regcache->arch (), gdbarch_tdep (regcache->arch ())->regs.r) != 32); +++ +++ if (have_ptrace_getregset == TRIBOOL_TRUE) +++ loongarch_store_regs (regcache, regnum); +++ else +++ linux_nat_trad_target::store_registers (regcache, regnum); +++} +++ +++ +++const struct target_desc * +++loongarch_linux_nat_target::read_description () +++{ +++ ensure_ptrace_getregset (); +++ return loongarch_linux_read_description_runtime (inferior_ptid.pid ()); +++} +++ +++void +++loongarch_linux_nat_target::loongarch_fetch_regs (struct regcache *regcache, int regno) +++{ +++ auto regs = &gdbarch_tdep (regcache->arch ())->regs; +++ pid_t tid = get_ptrace_pid (regcache->ptid ()); +++ +++ do +++ { +++ if (regs->r < 0) +++ break; +++ if (regno == -1); +++ else if (regs->r <= regno && regno < regs->r + 32); +++ else if (regs->pc == regno); +++ else if (regs->badvaddr == regno); +++ else +++ break; +++ +++ loongarch_elf_gregset_t regset; +++ struct iovec iovec = { .iov_base = ®set, .iov_len = sizeof (regset)}; +++ if (ptrace (PTRACE_GETREGSET, tid, NT_PRSTATUS, (long) &iovec) < 0) +++ perror_with_name (_("Couldn't get NT_PRSTATUS registers")); +++ else +++ loongarch_elf_gregset.supply_regset (NULL, regcache, regno, ®set, sizeof (regset)); +++ } +++ while (0); +++ +++ do +++ { +++ if (regs->f < 0) +++ break; +++ if (regno == -1); +++ else if (regs->f <= regno && regno < regs->f + 32); +++ else if (regs->fcc <= regno && regno < regs->fcc + 8); +++ else if (regs->fcsr == regno); +++ else +++ break; +++ +++ loongarch_elf_fpregset_t regset; +++ struct iovec iovec = { .iov_base = ®set, .iov_len = sizeof (regset)}; +++ if (ptrace (PTRACE_GETREGSET, tid, NT_FPREGSET, (long) &iovec) < 0) +++ perror_with_name (_("Couldn't get NT_FPREGSET registers")); +++ else +++ loongarch_elf_fpregset.supply_regset (NULL, regcache, regno, ®set, sizeof (regset)); +++ } +++ while (0); +++ +++ do +++ { +++ if (regs->scr < 0) +++ break; +++ else if (regno == -1); +++ else if (regs->scr <= regno && regno < regs->scr + 4); +++ else if (regs->EFLAG == regno); +++ else if (regs->lbt_top == regno); +++ else +++ break; +++ +++ loongarch_elf_lbtregset_t regset = {0}; +++ struct iovec iovec = { .iov_base = ®set, .iov_len = sizeof (regset)}; +++ if (ptrace (PTRACE_GETREGSET, tid, NT_LARCH_LBT, (long) &iovec) < 0) +++ perror_with_name (_("Couldn't get LTB registers")); +++ else +++ loongarch_elf_lbtregset.supply_regset (NULL, regcache, regno, ®set, sizeof (regset)); +++ } +++ while (0); +++ +++ do +++ { +++ if (regs->vr < 0) +++ break; +++ if (regno == -1); +++ else if (regs->vr <= regno && regno < regs->vr + 32); +++ else +++ break; +++ +++ loongarch_elf_lsxregset_t regset; +++ struct iovec iovec = { .iov_base = ®set, .iov_len = sizeof (regset)}; +++ if (ptrace (PTRACE_GETREGSET, tid, NT_LARCH_LSX, (long) &iovec) < 0) +++ perror_with_name (_("Couldn't get LSX registers")); +++ else +++ loongarch_elf_lsxregset.supply_regset (NULL, regcache, regno, ®set, sizeof (regset)); +++ } +++ while (0); +++ +++ do +++ { +++ if (regs->xr < 0) +++ break; +++ else if (regno == -1); +++ else if (regs->xr <= regno && regno < regs->xr + 32); +++ else +++ break; +++ +++ loongarch_elf_lasxregset_t regset; +++ struct iovec iovec = { .iov_base = ®set, .iov_len = sizeof (regset)}; +++ if (ptrace (PTRACE_GETREGSET, tid, NT_LARCH_LASX, (long) &iovec) < 0) +++ perror_with_name (_("Couldn't get LASX registers")); +++ else +++ loongarch_elf_lasxregset.supply_regset (NULL, regcache, regno, ®set, sizeof (regset)); +++ } +++ while (0); +++} +++ +++void +++loongarch_linux_nat_target::loongarch_store_regs (struct regcache *regcache, int regno) +++{ +++ auto regs = &gdbarch_tdep (regcache->arch ())->regs; +++ pid_t tid = get_ptrace_pid (regcache->ptid ()); +++ +++ do +++ { +++ if (regs->r < 0) +++ break; +++ if (regno == -1); +++ else if (regs->r <= regno && regno < regs->r + 32); +++ else if (regs->pc == regno); +++ else +++ break; +++ +++ loongarch_elf_gregset_t regset; +++ struct iovec iovec = { .iov_base = ®set, .iov_len = sizeof (regset)}; +++ if (ptrace (PTRACE_GETREGSET, tid, NT_PRSTATUS, (long) &iovec) < 0) +++ perror_with_name (_("Couldn't get NT_PRSTATUS registers")); +++ else +++ { +++ loongarch_elf_gregset.collect_regset (NULL, regcache, regno, ®set,sizeof (regset)); +++ if (ptrace (PTRACE_SETREGSET, tid, NT_PRSTATUS, (long) &iovec) < 0) +++ perror_with_name (_("Couldn't set NT_PRSTATUS registers")); +++ } +++ } +++ while (0); +++ +++ do +++ { +++ if (regs->f < 0) +++ break; +++ if (regno == -1); +++ else if (regs->f <= regno && regno < regs->f + 32); +++ else if (regs->fcc <= regno && regno < regs->fcc + 8); +++ else if (regs->fcsr == regno); +++ else +++ break; +++ +++ loongarch_elf_fpregset_t regset; +++ struct iovec iovec = { .iov_base = ®set, .iov_len = sizeof (regset)}; +++ if (ptrace (PTRACE_GETREGSET, tid, NT_FPREGSET, (long) &iovec) < 0) +++ perror_with_name (_("Couldn't get NT_FPREGSET registers")); +++ else +++ { +++ loongarch_elf_fpregset.collect_regset (NULL, regcache, regno, ®set,sizeof (regset)); +++ if (ptrace (PTRACE_SETREGSET, tid, NT_FPREGSET, (long) &iovec) < 0) +++ perror_with_name (_("Couldn't set NT_FPREGSET registers")); +++ } +++ } +++ while (0); +++ +++ do +++ { +++ if (regs->scr < 0) +++ break; +++ else if (regno == -1); +++ else if (regs->scr <= regno && regno < regs->scr + 4); +++ else if (regs->EFLAG == regno); +++ else if (regs->lbt_top == regno); +++ else +++ break; +++ +++ loongarch_elf_lbtregset_t regset; +++ struct iovec iovec = { .iov_base = ®set, .iov_len = sizeof (regset)}; +++ if (ptrace (PTRACE_GETREGSET, tid, NT_LARCH_LBT, (long) &iovec) < 0) +++ perror_with_name (_("Couldn't get LBT registers")); +++ else +++ { +++ loongarch_elf_lbtregset.collect_regset (NULL, regcache, regno, ®set,sizeof (regset)); +++ if (ptrace (PTRACE_SETREGSET, tid, NT_LARCH_LBT, (long) &iovec) < 0) +++ perror_with_name (_("Couldn't set LBT registers")); +++ } +++ } +++ while (0); +++ +++ do +++ { +++ if (regs->vr < 0) +++ break; +++ if (regno == -1); +++ else if (regs->vr <= regno && regno < regs->vr + 32); +++ else +++ break; +++ +++ loongarch_elf_lsxregset_t regset; +++ struct iovec iovec = { .iov_base = ®set, .iov_len = sizeof (regset)}; +++ if (ptrace (PTRACE_GETREGSET, tid, NT_LARCH_LSX, (long) &iovec) < 0) +++ perror_with_name (_("Couldn't get LSX registers")); +++ else +++ { +++ loongarch_elf_lsxregset.collect_regset (NULL, regcache, regno, ®set,sizeof (regset)); +++ if (ptrace (PTRACE_SETREGSET, tid, NT_LARCH_LSX, (long) &iovec) < 0) +++ perror_with_name (_("Couldn't set LSX registers")); +++ } +++ } +++ while (0); +++ +++ do +++ { +++ if (regs->xr < 0) +++ break; +++ else if (regno == -1); +++ else if (regs->xr <= regno && regno < regs->xr + 32); +++ else +++ break; +++ +++ loongarch_elf_lasxregset_t regset; +++ struct iovec iovec = { .iov_base = ®set, .iov_len = sizeof (regset)}; +++ if (ptrace (PTRACE_GETREGSET, tid, NT_LARCH_LASX, (long) &iovec) < 0) +++ perror_with_name (_("Couldn't get LASX registers")); +++ else +++ { +++ loongarch_elf_lasxregset.collect_regset (NULL, regcache, regno, ®set,sizeof (regset)); +++ if (ptrace (PTRACE_SETREGSET, tid, NT_LARCH_LASX, (long) &iovec) < 0) +++ perror_with_name (_("Couldn't set LASX registers")); +++ } +++ } +++ while (0); +++} +++ +++/* Return the address in the core dump or inferior of register REGNO. */ +++ +++CORE_ADDR +++loongarch_linux_nat_target::register_u_offset (struct gdbarch *gdbarch, +++ int regno, int store_p) +++{ +++ auto regs = &gdbarch_tdep (gdbarch)->regs; +++ /* according to */ +++ if (0 <= regs->r && regs->r <= regno && regno < regs->r + GPR_NUM) +++ return GPR_BASE + regno - regs->r; +++ else if (regs->pc == regno) +++ return PC; +++ return -1; +++} +++ +++ +++/* Implement the to_xfer_partial target_ops method. */ +++ +++enum target_xfer_status +++loongarch_linux_nat_target::xfer_partial (enum target_object object, +++ const char *annex, gdb_byte *readbuf, +++ const gdb_byte *writebuf, +++ ULONGEST offset, ULONGEST len, +++ ULONGEST *xfered_len) +++{ +++ pid_t pid = inferior_ptid.pid(); +++ +++ if (object != TARGET_OBJECT_LARCH) +++ return linux_nat_trad_target::xfer_partial +++ (object, annex, readbuf, writebuf, offset, len, xfered_len); +++ +++ if (strcmp (annex, "cpucfg") == 0) +++ { +++ if (writebuf) +++ return TARGET_XFER_E_IO; +++ if (offset % 4 != 0 || offset % 4 != 0) +++ return TARGET_XFER_E_IO; +++ char t_buf[offset + len]; +++ struct iovec iovec = { .iov_base = &t_buf, .iov_len = sizeof (t_buf)}; +++ if (ptrace (PTRACE_GETREGSET, pid, NT_LARCH_CPUCFG, &iovec) < 0) +++ { +++ size_t i; +++ for (i = offset / 4; i < (offset + len) / 4 + 1; i++) +++ ((uint32_t *)t_buf)[i] = loongarch_cpucfg (i); +++ } +++ memcpy (readbuf, t_buf + offset, len); +++ *xfered_len = len; +++ return TARGET_XFER_OK; +++ } +++ +++ return TARGET_XFER_E_IO; +++} +++ +++static loongarch_linux_nat_target the_loongarch_linux_nat_target; +++ +++/* Wrapper functions. These are only used by libthread_db. */ +++ +++void +++supply_gregset (struct regcache *regcache, +++ const gdb_gregset_t/* elf_gregset_t */ *gregset) +++{ +++ loongarch_elf_gregset.supply_regset +++ (NULL, regcache, -1, gregset, sizeof (gdb_gregset_t)); +++} +++ +++void +++fill_gregset (const struct regcache *regcache, +++ gdb_gregset_t/* elf_gregset_t */ *gregset, int regno) +++{ +++ loongarch_elf_gregset.collect_regset +++ (NULL, regcache, regno, gregset, sizeof (gdb_gregset_t)); +++} +++ +++void +++supply_fpregset (struct regcache *regcache, +++ const gdb_fpregset_t/* elf_fpregset_t */ *fpregset) +++{ +++ loongarch_elf_fpregset.supply_regset +++ (NULL, regcache, -1, fpregset, sizeof (gdb_fpregset_t)); +++} +++ +++void +++fill_fpregset (const struct regcache *regcache, +++ gdb_fpregset_t/* elf_fpregset_t */ *fpregset, int regno) +++{ +++ loongarch_elf_fpregset.collect_regset +++ (NULL, regcache, regno, fpregset, sizeof (gdb_fpregset_t)); +++} +++ +++/* -1 if the kernel and/or CPU do not support watch registers. +++ 1 if watch_readback is valid and we can read style, num_valid +++ and the masks. +++ 0 if we need to read the watch_readback. */ +++ +++static int watch_readback_valid; +++ +++/* Cached watch register read values. */ +++ +++static struct pt_watch_regs watch_readback = { .max_valid = MAX_DEBUG_REGISTER, }; +++ +++static struct loongarch_watchpoint *current_watches; +++ +++/* The current set of watch register values for writing the +++ registers. */ +++ +++static struct pt_watch_regs watch_mirror = { .max_valid = MAX_DEBUG_REGISTER, }; +++ +++static void +++loongarch_show_dr (const char *func, CORE_ADDR addr, +++ int len, enum target_hw_bp_type type) +++{ +++ int i; +++ +++ puts_unfiltered (func); +++ if (addr || len) +++ printf_unfiltered (" (addr=%s, len=%d, type=%s)", +++ paddress (target_gdbarch (), addr), len, +++ type == hw_write ? "data-write" +++ : (type == hw_read ? "data-read" +++ : (type == hw_access ? "data-read/write" +++ : (type == hw_execute ? "instruction-execute" +++ : "??unknown??")))); +++ puts_unfiltered (":\n"); +++ +++ for (i = 0; i < MAX_DEBUG_REGISTER; i++) +++ printf_unfiltered ("\tDR%d: addr=%s, mask=%s\n", i, +++ paddress (target_gdbarch (), +++ loongarch_linux_watch_get_addr (&watch_mirror, +++ i)), +++ paddress (target_gdbarch (), +++ loongarch_linux_watch_get_mask (&watch_mirror, +++ i))); +++} +++ +++/* Target to_can_use_hw_breakpoint implementation. Return 1 if we can +++ handle the specified watch type. */ +++ +++int +++loongarch_linux_nat_target::can_use_hw_breakpoint (enum bptype type, +++ int cnt, int ot) +++{ +++ int i; +++ uint32_t wanted_mask, irw_mask; +++ long lwp = inferior_ptid.lwp (); +++ +++ if (!loongarch_linux_read_watch_registers (lwp, +++ &watch_readback, +++ &watch_readback_valid, 0)) +++ return 0; +++ +++ switch (type) +++ { +++ case bp_hardware_watchpoint: +++ wanted_mask = W_MASK; +++ break; +++ case bp_read_watchpoint: +++ wanted_mask = R_MASK; +++ break; +++ case bp_access_watchpoint: +++ wanted_mask = R_MASK | W_MASK; +++ break; +++ case bp_hardware_breakpoint: +++ wanted_mask = I_MASK; +++ break; +++ default: +++ return 0; +++ } +++ +++ for (i = 0; +++ i < loongarch_linux_watch_get_num_valid (&watch_readback) && cnt; +++ i++) +++ { +++ irw_mask = loongarch_linux_watch_get_irwmask (&watch_readback, i); +++ if ((irw_mask & wanted_mask) == wanted_mask) +++ cnt--; +++ } +++ return (cnt == 0) ? 1 : 0; +++} +++ +++/* Target to_stopped_by_watchpoint implementation. Return 1 if +++ stopped by watchpoint. The watchhi R and W bits indicate the watch +++ register triggered. */ +++ +++bool +++loongarch_linux_nat_target::stopped_by_watchpoint () +++{ +++ int n; +++ int num_valid; +++ +++ if (!loongarch_linux_read_watch_registers (inferior_ptid.lwp (), +++ &watch_readback, +++ &watch_readback_valid, 1)) +++ return false; +++ +++ num_valid = loongarch_linux_watch_get_num_valid (&watch_readback); +++ +++ for (n = 0; n < MAX_DEBUG_REGISTER && n < num_valid; n++) +++ if (loongarch_linux_watch_get_irwstat (&watch_readback, n) & (R_MASK | W_MASK)) +++ return true; +++ +++ return false; +++} +++ +++/* Target to_stopped_data_address implementation. Set the address +++ where the watch triggered (if known). Return 1 if the address was +++ known. */ +++ +++bool +++loongarch_linux_nat_target::stopped_data_address (CORE_ADDR *paddr) +++{ +++ /* On mips we don't know the low order 3 bits of the data address, +++ so we must return false. */ +++#if 1 +++ int num_valid, n; +++ if (!loongarch_linux_read_watch_registers (inferior_ptid.lwp (), +++ &watch_readback, +++ &watch_readback_valid, 1)) +++ return false; +++ +++ num_valid = loongarch_linux_watch_get_num_valid (&watch_readback); +++ +++ for (n = 0; n < MAX_DEBUG_REGISTER && n < num_valid; n++) +++ if (loongarch_linux_watch_get_irwstat (&watch_readback, n) & (R_MASK | W_MASK)) { +++ CORE_ADDR t_addr, t_mask; +++ int t_irw; +++ struct loongarch_watchpoint *watch; +++ +++ t_addr = loongarch_linux_watch_get_addr (&watch_readback, n); +++ t_irw = loongarch_linux_watch_get_irw(&watch_readback, n) & IRW_MASK; +++ t_mask = loongarch_linux_watch_get_mask (&watch_readback, n); +++ +++ for (watch = current_watches; +++ watch != NULL; +++ watch = watch->next) +++ { +++ CORE_ADDR addr = watch->addr; +++ CORE_ADDR last_byte = addr + watch->len - 1; +++ +++ if ((t_irw & loongarch_linux_watch_type_to_irw (watch->type)) == 0) +++ { +++ /* Different type. */ +++ continue; +++ } +++ /* Check for overlap of even a single byte. */ +++ if (last_byte >= t_addr && addr <= t_addr + t_mask) { +++ *paddr = addr; +++ return true; +++ } +++ } +++ } +++#endif +++ return false; +++} +++ +++/* Target to_region_ok_for_hw_watchpoint implementation. Return 1 if +++ the specified region can be covered by the watch registers. */ +++ +++int +++loongarch_linux_nat_target::region_ok_for_hw_watchpoint (CORE_ADDR addr, int len) +++{ +++ struct pt_watch_regs dummy_regs; +++ int i; +++ +++ if (!loongarch_linux_read_watch_registers (inferior_ptid.lwp (), +++ &watch_readback, +++ &watch_readback_valid, 0)) +++ return 0; +++ +++ dummy_regs = watch_readback; +++ /* Clear them out. */ +++ for (i = 0; i < loongarch_linux_watch_get_num_valid (&dummy_regs); i++) { +++ loongarch_linux_watch_set_addr (&dummy_regs, i, 0); +++ loongarch_linux_watch_set_mask (&dummy_regs, i, 0); +++ loongarch_linux_watch_set_irw (&dummy_regs, i, 0); +++ } +++ return loongarch_linux_watch_try_one_watch (&dummy_regs, addr, len, 0); +++} +++ +++/* Write the mirrored watch register values for each thread. */ +++ +++static int +++write_watchpoint_regs (void) +++{ +++ struct lwp_info *lp; +++ int tid; +++ +++ ALL_LWPS (lp) +++ { +++ tid = lp->ptid.lwp(); +++ if (ptrace (PTRACE_SET_WATCH_REGS, tid, &watch_mirror, NULL) == -1) +++ perror_with_name (_("Couldn't write debug register")); +++ } +++ return 0; +++} +++ +++/* linux_nat_target::low_new_thread implementation. */ +++ +++void +++loongarch_linux_nat_target::low_new_thread (struct lwp_info *lp) +++{ +++ long tid = lp->ptid.lwp (); +++ +++ if (!loongarch_linux_read_watch_registers (tid, +++ &watch_readback, +++ &watch_readback_valid, 0)) +++ return; +++ +++ if (ptrace (PTRACE_SET_WATCH_REGS, tid, &watch_mirror, NULL) == -1) +++ perror_with_name (_("Couldn't write debug register")); +++} +++ +++/* Target to_insert_watchpoint implementation. Try to insert a new +++ watch. Return zero on success. */ +++ +++int +++loongarch_linux_nat_target::insert_watchpoint (CORE_ADDR addr, int len, +++ enum target_hw_bp_type type, +++ struct expression *cond) +++{ +++ struct pt_watch_regs regs= { .max_valid = MAX_DEBUG_REGISTER, }; +++ struct loongarch_watchpoint *new_watch; +++ struct loongarch_watchpoint **pw; +++ +++ int i; +++ int retval; +++ +++ if (!loongarch_linux_read_watch_registers (inferior_ptid.lwp (), +++ &watch_readback, +++ &watch_readback_valid, 0)) +++ return -1; +++ +++ if (len <= 0) +++ return -1; +++ +++ regs = watch_readback; +++ /* Add the current watches. */ +++ loongarch_linux_watch_populate_regs (current_watches, ®s); +++ +++ /* Now try to add the new watch. */ +++ if (!loongarch_linux_watch_try_one_watch (®s, addr, len, +++ loongarch_linux_watch_type_to_irw (type))) +++ return -1; +++ +++ /* It fit. Stick it on the end of the list. */ +++ new_watch = XNEW (struct loongarch_watchpoint); +++ new_watch->addr = addr; +++ new_watch->len = len; +++ new_watch->type = type; +++ new_watch->next = NULL; +++ +++ pw = ¤t_watches; +++ while (*pw != NULL) +++ pw = &(*pw)->next; +++ *pw = new_watch; +++ +++ watch_mirror = regs; +++ retval = write_watchpoint_regs (); +++ +++ if (show_debug_regs) +++ loongarch_show_dr ("insert_watchpoint", addr, len, type); +++ +++ return retval; +++} +++ +++/* Target to_remove_watchpoint implementation. Try to remove a watch. +++ Return zero on success. */ +++ +++int +++loongarch_linux_nat_target::remove_watchpoint (CORE_ADDR addr, int len, +++ enum target_hw_bp_type type, +++ struct expression *cond) +++{ +++ int retval; +++ int deleted_one; +++ +++ struct loongarch_watchpoint **pw; +++ struct loongarch_watchpoint *w; +++ +++ /* Search for a known watch that matches. Then unlink and free +++ it. */ +++ deleted_one = 0; +++ pw = ¤t_watches; +++ while ((w = *pw)) +++ { +++ if (w->addr == addr && w->len == len && w->type == type) +++ { +++ *pw = w->next; +++ xfree (w); +++ deleted_one = 1; +++ break; +++ } +++ pw = &(w->next); +++ } +++ +++ if (!deleted_one) +++ return -1; /* We don't know about it, fail doing nothing. */ +++ +++ /* At this point watch_readback is known to be valid because we +++ could not have added the watch without reading it. */ +++ gdb_assert (watch_readback_valid == 1); +++ +++ watch_mirror = watch_readback; +++ loongarch_linux_watch_populate_regs (current_watches, &watch_mirror); +++ +++ retval = write_watchpoint_regs (); +++ +++ if (show_debug_regs) +++ loongarch_show_dr ("remove_watchpoint", addr, len, type); +++ +++ return retval; +++} +++ +++/* Insert a hardware-assisted breakpoint at BP_TGT->reqstd_address. +++ Return 0 on success, -1 on failure. */ +++ +++int +++loongarch_linux_nat_target::insert_hw_breakpoint (struct gdbarch *gdbarch, +++ struct bp_target_info *bp_tgt) +++{ +++ int ret; +++ CORE_ADDR addr = bp_tgt->placed_address = bp_tgt->reqstd_address; +++ int len = 4; +++ const enum target_hw_bp_type type = hw_execute; +++ +++ gdbarch_breakpoint_from_pc (gdbarch, &addr, &len); +++ +++ if (show_debug_regs) +++ fprintf_unfiltered +++ (gdb_stdlog, +++ "insert_hw_breakpoint on entry (addr=0x%08lx, len=%d))\n", +++ (unsigned long) addr, len); +++ +++ ret = insert_watchpoint (addr, len, type, NULL); +++ return ret; +++} +++ +++/* Remove a hardware-assisted breakpoint at BP_TGT->placed_address. +++ Return 0 on success, -1 on failure. */ +++ +++int +++loongarch_linux_nat_target::remove_hw_breakpoint (struct gdbarch *gdbarch, +++ struct bp_target_info *bp_tgt) +++{ +++ int ret; +++ CORE_ADDR addr = bp_tgt->placed_address; +++ int len = 4; +++ const enum target_hw_bp_type type = hw_execute; +++ +++ gdbarch_breakpoint_from_pc (gdbarch, &addr, &len); +++ +++ if (show_debug_regs) +++ fprintf_unfiltered +++ (gdb_stdlog, "remove_hw_breakpoint on entry (addr=0x%08lx, len=%d))\n", +++ (unsigned long) addr, len); +++ +++ ret = remove_watchpoint (addr, len, type, NULL); +++ +++ return ret; +++} +++ +++/* Target to_close implementation. Free any watches and call the +++ super implementation. */ +++ +++void +++loongarch_linux_nat_target::close () +++{ +++ struct loongarch_watchpoint *w; +++ struct loongarch_watchpoint *nw; +++ +++ /* Clean out the current_watches list. */ +++ w = current_watches; +++ while (w) +++ { +++ nw = w->next; +++ xfree (w); +++ w = nw; +++ } +++ current_watches = NULL; +++ +++ linux_nat_trad_target::close (); +++} +++ +++void +++_initialize_loongarch_linux_nat (void) +++{ +++ add_setshow_boolean_cmd ("show-debug-regs", class_maintenance, +++ &show_debug_regs, _("\ +++Set whether to show variables that mirror the mips debug registers."), _("\ +++Show whether to show variables that mirror the mips debug registers."), _("\ +++Use \"on\" to enable, \"off\" to disable.\n\ +++If enabled, the debug registers values are shown when GDB inserts\n\ +++or removes a hardware breakpoint or watchpoint, and when the inferior\n\ +++triggers a breakpoint or watchpoint."), +++ NULL, +++ NULL, +++ &maintenance_set_cmdlist, +++ &maintenance_show_cmdlist); +++ +++ linux_target = &the_loongarch_linux_nat_target; +++ add_inf_child_target (&the_loongarch_linux_nat_target); +++} ++diff --git gdb-10.2/gdb/loongarch-linux-tdep.c gdb-10.2/gdb/loongarch-linux-tdep.c ++new file mode 100644 ++index 0000000..4268ac1 ++--- /dev/null +++++ gdb-10.2/gdb/loongarch-linux-tdep.c ++@@ -0,0 +1,564 @@ +++#include "defs.h" +++#include "inferior.h" +++#include "gdbcore.h" +++#include "target.h" +++#include "solib-svr4.h" +++#include "osabi.h" +++#include "loongarch-tdep.h" +++#include "frame.h" +++#include "regcache.h" +++#include "trad-frame.h" +++#include "tramp-frame.h" +++#include "gdbtypes.h" +++#include "objfiles.h" +++#include "solib.h" +++#include "solist.h" +++#include "symtab.h" +++#include "target-descriptions.h" +++#include "loongarch-linux-tdep.h" +++#include "glibc-tdep.h" +++#include "linux-tdep.h" +++#include "xml-syscall.h" +++#include "gdbsupport/gdb_signals.h" +++ +++static void +++loongarch_supply_elf_gregset (const struct regset *r, +++ struct regcache *regcache, +++ int regno, const void *gprs, size_t len) +++{ +++ auto regs = &gdbarch_tdep (regcache->arch ())->regs; +++ gdb_assert (0 <= regs->r && sizeof (loongarch_elf_gregset_t) <= len); +++ +++ if (regno == -1) +++ { +++ size_t i; +++ for (i = 0; i < 32; i++) +++ loongarch_supply_elf_gregset (r, regcache, regs->r + i, gprs, len); +++ loongarch_supply_elf_gregset (r, regcache, regs->pc, gprs, len); +++ loongarch_supply_elf_gregset (r, regcache, regs->badvaddr, gprs, len); +++ } +++ else if (regs->r == regno) +++ regcache->raw_supply_zeroed (regs->r); +++ else if (regs->r < regno && regno < regs->r + 32) +++ regcache->raw_supply (regno, (const uint64_t *) gprs + regno - regs->r); +++ else if (regs->pc == regno) +++ regcache->raw_supply (regno, (const uint64_t *) gprs + 32); +++ else if (regs->badvaddr == regno) +++ regcache->raw_supply (regno, (const uint64_t *) gprs + 33); +++} +++ +++static void +++loongarch_fill_elf_gregset (const struct regset *r, +++ const struct regcache *regcache, int regno, +++ void *gprs, size_t len) +++{ +++ auto regs = &gdbarch_tdep (regcache->arch ())->regs; +++ gdb_assert (0 <= regs->r && sizeof (loongarch_elf_gregset_t) <= len); +++ +++ if (regno == -1) +++ { +++ size_t i; +++ for (i = 0; i < 32; i++) +++ loongarch_fill_elf_gregset (r, regcache, regs->r + i, gprs, len); +++ loongarch_fill_elf_gregset (r, regcache, regs->pc, gprs, len); +++ loongarch_fill_elf_gregset (r, regcache, regs->badvaddr, gprs, len); +++ } +++ else if (regs->r <= regno && regno < regs->r + 32) +++ regcache->raw_collect (regno, (uint64_t *) gprs + regno - regs->r); +++ else if (regs->pc == regno) +++ regcache->raw_collect (regno, (uint64_t *) gprs + 32); +++ else if (regs->badvaddr == regno) +++ regcache->raw_collect (regno, (uint64_t *) gprs + 33); +++} +++ +++const struct regset loongarch_elf_gregset = { +++ NULL, loongarch_supply_elf_gregset, loongarch_fill_elf_gregset, +++}; +++ +++static void +++loongarch_supply_elf_fpregset (const struct regset *r, +++ struct regcache *regcache, +++ int regno, const void *fprs, size_t len) +++{ +++ auto regs = &gdbarch_tdep (regcache->arch ())->regs; +++ gdb_assert (0 <= regs->f && sizeof (loongarch_elf_fpregset_t) <= len); +++ +++ if (regno == -1) +++ { +++ size_t i; +++ for (i = 0; i < 32; i++) +++ loongarch_supply_elf_fpregset (r, regcache, regs->f + i, fprs, len); +++ for (i = 0; i < 8; i++) +++ loongarch_supply_elf_fpregset (r, regcache, regs->fcc + i, fprs, len); +++ loongarch_supply_elf_fpregset (r, regcache, regs->fcsr, fprs, len); +++ } +++ else if (regs->f <= regno && regno < regs->f + 32) +++ regcache->raw_supply (regno, (const uint64_t *) fprs + regno - regs->f); +++ else if (regs->fcc <= regno && regno < regs->fcc + 8) +++ { +++ const uint8_t *fcc = (const uint8_t *) ((const uint64_t *) fprs + 32); +++ regcache->raw_supply_integer (regno, fcc + regno - regs->fcc, 1, false); +++ } +++ else if (regs->fcsr == regno) +++ regcache->raw_supply_integer +++ (regno, (const gdb_byte *) ((const uint64_t *) fprs + 33), 4, false); +++} +++ +++static void +++loongarch_fill_elf_fpregset (const struct regset *r, +++ const struct regcache *regcache, int regno, +++ void *fprs, size_t len) +++{ +++ auto regs = &gdbarch_tdep (regcache->arch ())->regs; +++ gdb_assert (0 <= regs->f && sizeof (loongarch_elf_fpregset_t) <= len); +++ +++ if (regno == -1) +++ { +++ size_t i; +++ for (i = 0; i < 32; i++) +++ loongarch_fill_elf_fpregset (r, regcache, regs->f + i, fprs, len); +++ for (i = 0; i < 8; i++) +++ loongarch_fill_elf_fpregset (r, regcache, regs->fcc + i, fprs, len); +++ loongarch_fill_elf_fpregset (r, regcache, regs->fcsr, fprs, len); +++ } +++ else if (regs->f <= regno && regno < regs->f + 32) +++ regcache->raw_collect (regno, (uint64_t *) fprs + regno - regs->f); +++ else if (regs->fcc <= regno && regno < regs->fcc + 8) +++ { +++ uint8_t *fcc = (uint8_t *) ((uint64_t *) fprs + 32); +++ regcache->raw_collect (regno, fcc + regno - regs->fcc); +++ } +++ else if (regs->fcsr == regno) +++ regcache->raw_collect_integer +++ (regno, (gdb_byte *) ((uint64_t *) fprs + 33), 4, false); +++} +++ +++const struct regset loongarch_elf_fpregset = { +++ NULL, loongarch_supply_elf_fpregset, loongarch_fill_elf_fpregset, +++}; +++ +++static void +++loongarch_supply_elf_cpucfgregset (const struct regset *r, +++ struct regcache *regcache, +++ int regno, const void *cpucfgs, size_t len) +++{ +++} +++ +++static void +++loongarch_fill_elf_cpucfgregset (const struct regset *r, +++ const struct regcache *regcache, int regno, +++ void *cpucfgs, size_t len) +++{ +++ ULONGEST xfered_len; +++ target_xfer_partial (current_top_target (), TARGET_OBJECT_LARCH, "cpucfg", +++ (gdb_byte *) cpucfgs, NULL, 0, len, &xfered_len); +++ memset ((gdb_byte *) cpucfgs + xfered_len, 0, len - xfered_len); +++} +++ +++const struct regset loongarch_elf_cpucfgregset = { +++ NULL, loongarch_supply_elf_cpucfgregset, loongarch_fill_elf_cpucfgregset, +++}; +++ +++static void +++loongarch_supply_elf_lbtregset (const struct regset *r, +++ struct regcache *regcache, +++ int regno, const void *lbtrs, size_t len) +++{ +++ auto regs = &gdbarch_tdep (regcache->arch ())->regs; +++ gdb_assert (0 <= regs->scr && sizeof (loongarch_elf_lbtregset_t) <= len); +++ +++ if (regno == -1) +++ { +++ size_t i; +++ for (i = 0; i < 4; i++) +++ loongarch_supply_elf_lbtregset (r, regcache, regs->scr + i, lbtrs, len); +++ loongarch_supply_elf_lbtregset (r, regcache, regs->EFLAG, lbtrs, len); +++ loongarch_supply_elf_lbtregset (r, regcache, regs->lbt_top, lbtrs, len); +++ } +++ else if (regs->scr <= regno && regno < regs->scr + 4) +++ regcache->raw_supply (regno, (const uint64_t *) lbtrs + regno - regs->scr); +++ else if (regs->EFLAG == regno) +++ regcache->raw_supply (regno, (const uint64_t *) lbtrs + 4); +++ else if (regs->lbt_top == regno) +++ regcache->raw_supply (regno, (const uint32_t *) lbtrs + 9); +++} +++ +++static void +++loongarch_fill_elf_lbtregset (const struct regset *r, +++ const struct regcache *regcache, int regno, +++ void *lbtrs, size_t len) +++{ +++ auto regs = &gdbarch_tdep (regcache->arch ())->regs; +++ gdb_assert (0 <= regs->scr && sizeof (loongarch_elf_lbtregset_t) <= len); +++ +++ if (regno == -1) +++ { +++ size_t i; +++ for (i = 0; i < 4; i++) +++ loongarch_fill_elf_lbtregset (r, regcache, regs->scr + i, lbtrs, len); +++ loongarch_fill_elf_lbtregset (r, regcache, regs->EFLAG, lbtrs, len); +++ loongarch_fill_elf_lbtregset (r, regcache, regs->lbt_top, lbtrs, len); +++ } +++ else if (regs->scr <= regno && regno < regs->scr + 4) +++ regcache->raw_collect (regno, (uint64_t *) lbtrs + regno - regs->scr); +++ else if (regs->EFLAG == regno) +++ regcache->raw_collect (regno, (uint64_t *) lbtrs + 4); +++ else if (regs->lbt_top == regno) +++ regcache->raw_collect (regno, (uint32_t *) lbtrs + 9); +++} +++ +++const struct regset loongarch_elf_lbtregset = { +++ NULL, loongarch_supply_elf_lbtregset, loongarch_fill_elf_lbtregset, +++}; +++ +++static void +++loongarch_supply_elf_lsxregset (const struct regset *r, +++ struct regcache *regcache, +++ int regno, const void *lsxrs, size_t len) +++{ +++ size_t i; +++ auto regs = &gdbarch_tdep (regcache->arch ())->regs; +++ gdb_assert (0 <= regs->vr && sizeof (loongarch_elf_lsxregset_t) <= len); +++ +++ if (regno == -1) +++ for (i = 0; i < 32; i++) +++ loongarch_supply_elf_lsxregset (r, regcache, regs->vr + i, lsxrs, len); +++ else if (regs->vr <= regno && regno < regs->vr + 32) +++ regcache->raw_supply +++ (regno, (const char *) lsxrs + (regno - regs->vr) * 16); +++} +++ +++static void +++loongarch_fill_elf_lsxregset (const struct regset *r, +++ const struct regcache *regcache, int regno, +++ void *lsxrs, size_t len) +++{ +++ size_t i; +++ auto regs = &gdbarch_tdep (regcache->arch ())->regs; +++ gdb_assert (0 <= regs->vr && sizeof (loongarch_elf_lsxregset_t) <= len); +++ +++ if (regno == -1) +++ for (i = 0; i < 32; i++) +++ loongarch_fill_elf_lsxregset (r, regcache, regs->vr + i, lsxrs, len); +++ else if (regs->vr <= regno && regno < regs->vr + 32) +++ regcache->raw_collect (regno, (char *) lsxrs + (regno - regs->vr) * 16); +++} +++ +++const struct regset loongarch_elf_lsxregset = { +++ NULL, loongarch_supply_elf_lsxregset, loongarch_fill_elf_lsxregset, +++}; +++ +++static void +++loongarch_supply_elf_lasxregset (const struct regset *r, +++ struct regcache *regcache, +++ int regno, const void *lasxrs, size_t len) +++{ +++ size_t i; +++ auto regs = &gdbarch_tdep (regcache->arch ())->regs; +++ gdb_assert (0 <= regs->xr && sizeof (loongarch_elf_lasxregset_t) <= len); +++ +++ if (regno == -1) +++ for (i = 0; i < 32; i++) +++ loongarch_supply_elf_lasxregset (r, regcache, regs->xr + i, lasxrs, len); +++ else if (regs->xr <= regno && regno < regs->xr + 32) +++ regcache->raw_supply +++ (regno, (const char *) lasxrs + (regno - regs->xr) * 32); +++} +++ +++static void +++loongarch_fill_elf_lasxregset (const struct regset *r, +++ const struct regcache *regcache, int regno, +++ void *lasxrs, size_t len) +++{ +++ size_t i; +++ auto regs = &gdbarch_tdep (regcache->arch ())->regs; +++ gdb_assert (0 <= regs->xr && sizeof (loongarch_elf_lasxregset_t) <= len); +++ +++ if (regno == -1) +++ for (i = 0; i < 32; i++) +++ loongarch_fill_elf_lasxregset (r, regcache, regs->xr + i, lasxrs, len); +++ else if (regs->xr <= regno && regno < regs->xr + 32) +++ regcache->raw_collect (regno, (char *) lasxrs + (regno - regs->xr) * 32); +++} +++ +++const struct regset loongarch_elf_lasxregset = { +++ NULL, loongarch_supply_elf_lasxregset, loongarch_fill_elf_lasxregset, +++}; +++ +++static void +++loongarch_linux_iterate_over_regset_sections (struct gdbarch *gdbarch, +++ iterate_over_regset_sections_cb *cb, +++ void *cb_data, +++ const struct regcache *regcache) +++{ +++ auto regs = &gdbarch_tdep (gdbarch)->regs; +++ if (0 <= regs->r) +++ cb (".reg", sizeof (loongarch_elf_gregset_t), +++ sizeof (loongarch_elf_gregset_t), &loongarch_elf_gregset, NULL, cb_data); +++ if (0 <= regs->f) +++ cb (".reg2", sizeof (loongarch_elf_fpregset_t), +++ sizeof (loongarch_elf_gregset_t), &loongarch_elf_gregset, NULL, cb_data); +++ do +++ { +++ uint32_t t; +++ ULONGEST xfered_len; +++ if (target_xfer_partial (current_top_target (), TARGET_OBJECT_LARCH, +++ "cpucfg", (gdb_byte *) &t, NULL, 0, sizeof (t), +++ &xfered_len) != TARGET_XFER_OK) +++ break; +++ cb (".reg-loongarch-cpucfg", 64 * 4, 64 * 4, &loongarch_elf_cpucfgregset, +++ "Loongarch CPU config", cb_data); +++ } +++ while (0); +++ if (0 <= regs->scr) +++ cb (".reg-loongarch-lbt", sizeof (loongarch_elf_lbtregset_t), +++sizeof (loongarch_elf_lbtregset_t), &loongarch_elf_lbtregset, "Loongson Binary Translation", cb_data); +++ if (0 <= regs->vr) +++ cb (".reg-loongarch-lsx", sizeof (loongarch_elf_lsxregset_t), +++sizeof (loongarch_elf_lbtregset_t), &loongarch_elf_lsxregset, "Loongson SIMD Extension", cb_data); +++ if (0 <= regs->xr) +++ cb (".reg-loongarch-lasx", sizeof (loongarch_elf_lasxregset_t), +++sizeof (loongarch_elf_lbtregset_t), &loongarch_elf_lasxregset, "Loongson Advanced SIMD Extension", cb_data); +++} +++ +++static const struct target_desc * +++loongarch_linux_core_read_description (struct gdbarch *gdbarch, +++ struct target_ops *target, bfd *abfd) +++{ +++ int rlen, fpu32, fpu64, lbt, lsx, lasx; +++ +++ /* 约定regset中的寄存器大小恒为64位,即使是在32位机器中,更高部分是低32位 +++ 的符号扩展 */ +++ rlen = 64; +++ fpu32 = 0; +++ +++ fpu64 = !!bfd_get_section_by_name (abfd, ".reg2"); +++ lbt = !!bfd_get_section_by_name (abfd, ".reg-loongarch-lbt"); +++ lsx = !!bfd_get_section_by_name (abfd, ".reg-loongarch-lsx"); +++ lasx = !!bfd_get_section_by_name (abfd, ".reg-loongarch-lasx"); +++ +++ return +++ loongarch_create_target_description (rlen, fpu32, fpu64, lbt, lsx, lasx); +++} +++ +++//enum LARCH_BP_KIND +++//{ +++// LARCH_BP_GNU_LINUX_NORMAL, +++//}; +++// +++///* Implement the breakpoint_kind_from_pc gdbarch method. */ +++// +++//static int +++//loongarch_breakpoint_kind_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr) +++//{ +++// return LARCH_BP_GNU_LINUX_NORMAL; +++//} +++// +++///* Implement the sw_breakpoint_from_kind gdbarch method. */ +++// +++//static const gdb_byte * +++//loongarch_sw_breakpoint_from_kind (struct gdbarch *gdbarch, int kind, int *size) +++//{ +++// switch (kind) +++// { +++// case LARCH_BP_GNU_LINUX_NORMAL: +++// { +++// static const gdb_byte break_5[] = +++// { 0x05, 0x00, 0x2a, 0x00 }; /* break BRK_SSTEPBP(5) */ +++// *size = 4; +++// return break_5; +++// } +++// default: +++// gdb_assert_not_reached (_("unhandled breakpoint kind")); +++// } +++//} +++ +++static void +++loongarch_linux_lp64_sigframe_init (const struct tramp_frame *self, +++ struct frame_info *this_frame, +++ struct trad_frame_cache *this_cache, +++ CORE_ADDR func) +++{ +++ struct gdbarch *gdbarch = get_frame_arch (this_frame); +++ auto regs = &gdbarch_tdep (gdbarch)->regs; +++ CORE_ADDR frame_sp = get_frame_sp (this_frame); +++ +++/* +++ struct sigcontext { +++ __u64 sc_pc; +++ __u64 sc_regs[32]; +++ __u32 sc_flags; +++ +++ __u32 sc_fcsr; +++ __u32 sc_vcsr; +++ __u64 sc_fcc; +++ union fpureg sc_fpregs[32] FPU_ALIGN; +++ +++ #if defined(CONFIG_CPU_HAS_LBT) +++ __u64 sc_scr[4]; +++ #endif +++ __u32 sc_reserved; +++ }; +++ +++ typedef struct _sig_ucontext { +++ unsigned long uc_flags; +++ struct _sig_ucontext *uc_link; +++ stack_t uc_stack; +++ struct sigcontext uc_mcontext; +++ sigset_t uc_sigmask; +++ } _sig_ucontext_t; +++ +++ struct rt_sigframe { +++ unsigned int ass[4]; +++ unsigned int trampoline[2]; +++ siginfo_t info; +++ _sig_ucontext_t uc; +++ }; +++ +++ For returning from signal handler, '$sp' at VDSO sigreturn stub is +++ a instance of 'struct rt_sigframe'. We want 'sc_pc' and 'sc_regs'. +++ 'sc_pc' is '$sp + 224' +++ 'sc_regs' is '$sp + 232' +++ We just care the information to backtrace, others are ignored. +++*/ +++ +++ CORE_ADDR sigcontext_base = frame_sp + 224; +++ int i; +++ +++ trad_frame_set_reg_addr (this_cache, regs->pc, sigcontext_base); +++ for (i = 0; i < 32; i++) +++ trad_frame_set_reg_addr (this_cache, regs->r + i, +++ sigcontext_base + 8 + i * 8); +++ +++ trad_frame_set_id (this_cache, frame_id_build (frame_sp, func)); +++} +++ +++static const struct tramp_frame loongarch_linux_lp64_rt_sigframe = { +++ SIGTRAMP_FRAME, +++ 4, +++ { /* From $kernel/arch/loongarch/vdso/sigreturn.S. */ +++ /* ori $r11, $r0, 0x8b(__NR_rt_sigreturn) */ +++ { 0x03822c0b, ULONGEST_MAX }, +++ { 0x002b0000, ULONGEST_MAX }, /* syscall 0 */ +++ { TRAMP_SENTINEL_INSN, ULONGEST_MAX } }, +++ loongarch_linux_lp64_sigframe_init, +++ NULL +++}; +++ +++/* Return the current system call's number present in the +++ a7 register. When the function fails, it returns -1. */ +++ +++static LONGEST +++loongarch_linux_get_syscall_number (struct gdbarch *gdbarch, +++ thread_info *thread) +++{ +++ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); +++ auto regs = &tdep->regs; +++ struct regcache *regcache = get_thread_regcache (thread); +++ LONGEST ret; +++ +++ switch (tdep->ef_abi) +++ { +++ case EF_LARCH_ABI_LP64: +++ if (REG_VALID == regcache_cooked_read_signed +++ (regcache, regs->r + 11, &ret)) +++ return ret; +++ } +++ +++ return -1; +++} +++ +++static CORE_ADDR +++loongarch_linux_syscall_next_pc (struct frame_info *frame) +++{ +++ struct gdbarch *gdbarch = get_frame_arch (frame); +++ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); +++ auto regs = &tdep->regs; +++ CORE_ADDR pc = get_frame_pc (frame); +++ ULONGEST a7 = get_frame_register_unsigned (frame, regs->r + 11); +++ +++ switch (tdep->ef_abi) +++ { +++ case EF_LARCH_ABI_LP64: +++ /* If we are about to make a sigreturn syscall, use the unwinder to +++ decode the signal frame. */ +++ if (a7 == 0x8b/* LP64: __NR_rt_sigreturn */) +++ return frame_unwind_caller_pc (get_current_frame ()); +++ } +++ +++ return -1; +++} +++ +++static int +++loongarch_linux_syscall_record (struct regcache *regcache, unsigned long svc_number) +++{ +++ fprintf_unfiltered (gdb_stdout, "DEBUG INFO:FUNCTION loongarch_linux_syscall_record is called"); +++ return 0; +++} +++ +++static void +++loongarch_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) +++{ +++ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); +++ const struct target_desc *tdesc = info.target_desc; +++ struct tdesc_arch_data *tdesc_data = info.tdesc_data; +++ const struct tdesc_feature *feature; +++ int valid_p; +++ +++// gdb_assert (tdesc_data); +++ +++ linux_init_abi (info, gdbarch); +++ +++ switch (tdep->ef_abi) +++ { +++ case EF_LARCH_ABI_LP32: +++ set_solib_svr4_fetch_link_map_offsets +++ (gdbarch, svr4_ilp32_fetch_link_map_offsets); +++ break; +++ case EF_LARCH_ABI_XLP32: +++ set_solib_svr4_fetch_link_map_offsets +++ (gdbarch, svr4_ilp32_fetch_link_map_offsets); +++ break; +++ case EF_LARCH_ABI_LP64: +++ set_solib_svr4_fetch_link_map_offsets +++ (gdbarch, svr4_lp64_fetch_link_map_offsets); +++ tramp_frame_prepend_unwinder +++ (gdbarch, &loongarch_linux_lp64_rt_sigframe); +++ tdep->syscall_next_pc = loongarch_linux_syscall_next_pc; +++ +++ /* Functions for 'catch syscall'. */ +++ set_gdbarch_get_syscall_number +++ (gdbarch, loongarch_linux_get_syscall_number); +++ break; +++ } +++// set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target); +++ +++ /* GNU/Linux uses the dynamic linker included in the GNU C Library. */ +++ set_gdbarch_skip_solib_resolver (gdbarch, glibc_skip_solib_resolver); +++ +++ /* Enable TLS support. */ +++ set_gdbarch_fetch_tls_load_module_address +++ (gdbarch, svr4_fetch_objfile_link_map); +++ +++ /* Information about the target architecture. */ +++ //set_gdbarch_breakpoint_kind_from_pc (gdbarch, loongarch_breakpoint_kind_from_pc); +++ //set_gdbarch_sw_breakpoint_from_kind (gdbarch, loongarch_sw_breakpoint_from_kind); +++ set_gdbarch_call_dummy_location (gdbarch, AT_ENTRY_POINT); +++ +++ /* Core file support. */ +++ set_gdbarch_iterate_over_regset_sections +++ (gdbarch, loongarch_linux_iterate_over_regset_sections); +++ set_gdbarch_core_read_description +++ (gdbarch, loongarch_linux_core_read_description); +++ +++ set_gdbarch_process_record(gdbarch, loongarch_process_record); +++ tdep->loongarch_syscall_record = loongarch_linux_syscall_record; +++} +++ +++void +++_initialize_loongarch_linux_tdep (void) +++{ +++ gdbarch_register_osabi (bfd_arch_loongarch, bfd_mach_loongarch32 /* GDB may not care what arch variant is this. +++ So we specify DEFAULT_BFD_ARCH */, +++ GDB_OSABI_LINUX, loongarch_linux_init_abi); +++} ++diff --git gdb-10.2/gdb/loongarch-linux-tdep.h gdb-10.2/gdb/loongarch-linux-tdep.h ++new file mode 100644 ++index 0000000..e29b2d2 ++--- /dev/null +++++ gdb-10.2/gdb/loongarch-linux-tdep.h ++@@ -0,0 +1,28 @@ +++#ifndef LOONGARCH_LINUX_TDEP_H +++#define LOONGARCH_LINUX_TDEP_H +++ +++#include +++ +++#define ELF_NGREG 45 +++#define ELF_NFPREG 34 +++ +++typedef uint64_t loongarch_elf_gregset_t[ELF_NGREG]; +++extern const struct regset loongarch_elf_gregset; +++ +++typedef uint64_t loongarch_elf_fpregset_t[ELF_NFPREG]; +++extern const struct regset loongarch_elf_fpregset; +++ +++/* regset variable size */ +++extern const struct regset loongarch_elf_cpucfg; +++ +++/* 4 SCRs + 4-byte EFLAG + 1-byte lbt_top */ +++typedef uint64_t loongarch_elf_lbtregset_t[6]; +++extern const struct regset loongarch_elf_lbtregset; +++ +++typedef uint64_t loongarch_elf_lsxregset_t[32 * 2]; +++extern const struct regset loongarch_elf_lsxregset; +++ +++typedef uint64_t loongarch_elf_lasxregset_t[32 * 4]; +++extern const struct regset loongarch_elf_lasxregset; +++ +++#endif ++diff --git gdb-10.2/gdb/loongarch-tdep.c gdb-10.2/gdb/loongarch-tdep.c ++new file mode 100644 ++index 0000000..4d38857 ++--- /dev/null +++++ gdb-10.2/gdb/loongarch-tdep.c ++@@ -0,0 +1,2613 @@ +++/* Target-dependent code for the RISC-V architecture, for GDB. +++ +++ Copyright (C) 2018 Free Software Foundation, Inc. +++ +++ This file is part of GDB. +++ +++ This program is free software; you can redistribute it and/or modify +++ it under the terms of the GNU General Public License as published by +++ the Free Software Foundation; either version 3 of the License, or +++ (at your option) any later version. +++ +++ This program is distributed in the hope that it will be useful, +++ but WITHOUT ANY WARRANTY; without even the implied warranty of +++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +++ GNU General Public License for more details. +++ +++ You should have received a copy of the GNU General Public License +++ along with this program. If not, see . */ +++ +++#include "defs.h" +++#include "frame.h" +++#include "inferior.h" +++#include "symtab.h" +++#include "value.h" +++#include "gdbcmd.h" +++#include "language.h" +++#include "gdbcore.h" +++#include "symfile.h" +++#include "objfiles.h" +++#include "gdbtypes.h" +++#include "target.h" +++#include "arch-utils.h" +++#include "regcache.h" +++#include "osabi.h" +++#include "block.h" +++#include "reggroups.h" +++#include "elf-bfd.h" +++#include "symcat.h" +++#include "dis-asm.h" +++#include "frame-unwind.h" +++#include "frame-base.h" +++#include "trad-frame.h" +++#include "infcall.h" +++#include "floatformat.h" +++#include "remote.h" +++#include "target-descriptions.h" +++#include "dwarf2/frame.h" +++#include "user-regs.h" +++#include "valprint.h" +++#include "gdbsupport/common-defs.h" +++#include "cli/cli-decode.h" +++#include "observable.h" +++#include "target-float.h" +++#include "loongarch-tdep.h" +++#include "arch/loongarch.h" +++#include "record.h" +++#include "record-full.h" +++#include "arch/loongarch-insn.h" +++ +++ +++/* Description The location of saved registers in this buffer +++ (in particular the PC to use after longjmp is called) varies +++ depending on the ABI or the C Library. */ +++ +++#define LOONGARCH_JB_PC 0 +++ +++#define TYPE_CODE(t) (t->code ()) +++#define TYPE_TAG_NAME(t) (TYPE_MAIN_TYPE(t)->name) +++#define TYPE_NFIELDS(t) (t->num_fields ()) +++#define TYPE_NAME(t) (t->name ()) +++ +++static int +++loongarch_rlen (struct gdbarch *gdbarch) +++{ +++ switch (gdbarch_tdep (gdbarch)->ef_abi) +++ { +++ case EF_LARCH_ABI_LP64: +++ case EF_LARCH_ABI_XLP32: +++ return 64; +++ case EF_LARCH_ABI_LP32: +++ return 32; +++ default: +++ gdb_assert_not_reached ("unknown ABI"); +++ } +++ return 0; +++} +++ +++static insn_t +++loongarch_fetch_instruction (CORE_ADDR addr, int *errp) +++{ +++ /* 本意是传入足够的信息得到指令长度,目前不是变长指令,无所谓了 */ +++ size_t insnlen = loongarch_insn_length (0); +++ gdb_byte buf[insnlen]; +++ int err; +++ ULONGEST ret; +++ +++ err = target_read_memory (addr, buf, insnlen); +++ if (errp != NULL) +++ *errp = err; +++ if (err != 0) +++ { +++ if (errp == NULL) +++ memory_error (TARGET_XFER_E_IO, addr); +++ return 0; +++ } +++ ret = extract_unsigned_integer (buf, insnlen, BFD_ENDIAN_LITTLE); +++ return ret; +++} +++ +++static int +++loongarch_insn_is_branch_and_must_branch (insn_t insn) +++{ +++ if ((insn & 0xfc000000) == 0x4c000000 /* jirl r0:5,r5:5,s10:16<<2 */ +++ || (insn & 0xfc000000) == 0x50000000 /* b sb0:10|10:16<<2 */ +++ || (insn & 0xfc000000) == 0x54000000 /* bl sb0:10|10:16<<2 */ +++ || (insn & 0xfc0003e0) == 0x48000200 /* jiscr0 s0:5|10:16<<2 */ +++ || (insn & 0xfc0003e0) == 0x48000300) /* jiscr1 s0:5|10:16<<2 */ +++ return 1; +++ return 0; +++} +++ +++static int +++loongarch_insn_is_branch (insn_t insn) +++{ +++ if (loongarch_insn_is_branch_and_must_branch (insn) +++ || (insn & 0xfc000000) == 0x40000000 /* beqz r5:5,sb0:5|10:16<<2 */ +++ || (insn & 0xfc000000) == 0x44000000 /* bnez r5:5,sb0:5|10:16<<2 */ +++ || (insn & 0xfc000300) == 0x48000000 /* bceqz c5:3,sb0:5|10:16<<2 */ +++ || (insn & 0xfc000300) == 0x48000100 /* bcnez c5:3,sb0:5|10:16<<2 */ +++ || (insn & 0xfc000000) == 0x58000000 /* beq r5:5,r0:5,sb10:16<<2 */ +++ || (insn & 0xfc000000) == 0x5c000000 /* bne r5:5,r0:5,sb10:16<<2 */ +++ || (insn & 0xfc000000) == 0x60000000 /* blt r5:5,r0:5,sb10:16<<2 */ +++ || (insn & 0xfc000000) == 0x64000000 /* bge r5:5,r0:5,sb10:16<<2 */ +++ || (insn & 0xfc000000) == 0x68000000 /* bltu r5:5,r0:5,sb10:16<<2 */ +++ || (insn & 0xfc000000) == 0x6c000000) /* bgeu r5:5,r0:5,sb10:16<<2 */ +++ return 1; +++ return 0; +++} +++ +++static CORE_ADDR +++loongarch_next_pc_if_branch (struct regcache *regcache, CORE_ADDR cur_pc, insn_t insn) +++{ +++ struct gdbarch *gdbarch = regcache->arch (); +++ auto regs = &gdbarch_tdep (gdbarch)->regs; +++ CORE_ADDR next_pc; +++ +++ if ((insn & 0xfc000000) == 0x40000000 /* beqz r5:5,sb0:5|10:16<<2 */ +++ || (insn & 0xfc000000) == 0x44000000 /* bnez r5:5,sb0:5|10:16<<2 */ +++ || (insn & 0xfc000300) == 0x48000000 /* bceqz c5:3,sb0:5|10:16<<2 */ +++ || (insn & 0xfc000300) == 0x48000100) /* bcnez c5:3,sb0:5|10:16<<2 */ +++ next_pc = cur_pc + loongarch_decode_imm ("0:5|10:16<<2", insn, 1); +++ else if ((insn & 0xfc0003e0) == 0x48000200) /* jiscr0 s0:5|10:16<<2 */ +++ { +++ gdb_assert (0 <= regs->scr); +++ next_pc = regcache_raw_get_signed (regcache, regs->scr) +++ + loongarch_decode_imm ("0:5|10:16<<2", insn, 1); +++ } +++ else if ((insn & 0xfc0003e0) == 0x48000300) /* jiscr1 s0:5|10:16<<2 */ +++ { +++ gdb_assert (0 <= regs->scr); +++ next_pc = regcache_raw_get_signed (regcache, regs->scr + 1) +++ + loongarch_decode_imm ("0:5|10:16<<2", insn, 1); +++ } +++ else if ((insn & 0xfc000000) == 0x4c000000) /* jirl r0:5,r5:5,s10:16<<2 */ +++ next_pc = regcache_raw_get_signed +++ (regcache, regs->r + loongarch_decode_imm ("5:5", insn, 0)) +++ + loongarch_decode_imm ("10:16<<2", insn, 1); +++ else if ((insn & 0xfc000000) == 0x50000000 /* b sb0:10|10:16<<2 */ +++ || (insn & 0xfc000000) == 0x54000000)/* bl sb0:10|10:16<<2 */ +++ next_pc = cur_pc + loongarch_decode_imm ("0:10|10:16<<2", insn, 1); +++ else if ((insn & 0xfc000000) == 0x58000000 /* beq r5:5,r0:5,sb10:16<<2 */ +++ || (insn & 0xfc000000) == 0x5c000000 /* bne r5:5,r0:5,sb10:16<<2 */ +++ || (insn & 0xfc000000) == 0x60000000 /* blt r5:5,r0:5,sb10:16<<2 */ +++ || (insn & 0xfc000000) == 0x64000000 /* bge r5:5,r0:5,sb10:16<<2 */ +++ || (insn & 0xfc000000) == 0x68000000 /* bltu r5:5,r0:5,sb10:16<<2 */ +++ || (insn & 0xfc000000) == 0x6c000000)/* bgeu r5:5,r0:5,sb10:16<<2 */ +++ next_pc = cur_pc + loongarch_decode_imm ("10:16<<2", insn, 1); +++ else +++ gdb_assert_not_reached ("I don't know what branch is this"); +++ +++ return next_pc; +++} +++ +++/* Checks for an atomic sequence of instructions beginning with a LL/LLD +++ instruction and ending with a SC/SCD instruction. If such a sequence +++ is found, attempt to step through it. A breakpoint is placed at the end of +++ the sequence. */ +++ +++static std::vector +++loongarch_deal_with_atomic_sequence (struct regcache *regcache, CORE_ADDR pc) +++{ +++ struct gdbarch *gdbarch = regcache->arch (); +++ CORE_ADDR next_pc; +++ std::vector next_pcs; +++ insn_t insn = loongarch_fetch_instruction (pc, NULL); +++ size_t insnlen = loongarch_insn_length (insn); +++ int i, atomic_sequence_length, found_atomic_sequence_endpoint; +++ +++ /* 这个函数由loongarch_software_single_step调用,在single step时尝试找到原子 +++ 指令序列的终点。返回的CORE_ADDR向量似乎意味着控制流的所有可能去处。 +++ 如果 return {} 则意味着认为接下来的指令不属于原子操作。 */ +++ +++ if ((insn & 0xff000000) != 0x20000000 /* ll.w */ +++ && (insn & 0xff000000) != 0x22000000) /* ll.d */ +++ return {}; +++ +++ if (loongarch_debug) +++ fprintf_unfiltered (gdb_stdlog, +++"Single step: PC: %s OK, I found ll\\.[wd] here. It's atomic sequence?\n", +++ paddress (gdbarch, pc)); +++ +++ atomic_sequence_length = 30; /* Magic. */ +++ found_atomic_sequence_endpoint = 0; +++ for (pc += insnlen, i = 0; i < atomic_sequence_length; pc += insnlen, i++) +++ { +++ insn = loongarch_fetch_instruction (pc, NULL); +++ insnlen = loongarch_insn_length (insn); +++ +++ if (loongarch_insn_is_branch_and_must_branch (insn)) +++ { +++ if (loongarch_debug) +++ fprintf_unfiltered (gdb_stdlog, +++ "Single step: PC: %s Must branch here. Treat it normally.\n", +++ paddress (gdbarch, pc)); +++ break; +++ } +++ else if (loongarch_insn_is_branch (insn)) +++ { +++ next_pc = loongarch_next_pc_if_branch (regcache, pc, insn); +++ +++ if (loongarch_debug) +++ fprintf_unfiltered (gdb_stdlog, +++"Single step: PC: %s May branch inside and target is %s. Breakpoint there.\n", +++paddress (gdbarch, pc), paddress (gdbarch, next_pc)); +++ +++ next_pcs.push_back (next_pc); +++ } +++ else if ((insn & 0xff000000) == 0x21000000 /* sc.w */ +++ || (insn & 0xff000000) == 0x23000000) /* sc.d */ +++ { +++ found_atomic_sequence_endpoint = 1; +++ next_pc = pc + insnlen; +++ +++ if (loongarch_debug) +++ fprintf_unfiltered (gdb_stdlog, +++"Single step: PC: %s I found sc\\.[wd] and atomic sequence ends at here.\n" +++"Breakpoint next pc: %s.\n", +++paddress (gdbarch, pc), paddress (gdbarch, next_pc)); +++ +++ next_pcs.push_back (next_pc); +++ break; +++ } +++ } +++ +++ if (!found_atomic_sequence_endpoint) +++ { +++ if (loongarch_debug) +++ fprintf_unfiltered (gdb_stdlog, +++ "Single step: PC: %s Not ends with sc\\.[wd] in %d insns?\n" +++ "Treat it as not atomic sequence.\n", +++ paddress (gdbarch, pc), atomic_sequence_length); +++ +++ return {}; +++ } +++ +++ return next_pcs; +++} +++ +++/* mips_software_single_step() is called just before we want to resume +++ the inferior, if we want to single-step it but there is no hardware +++ or kernel single-step support (MIPS on GNU/Linux for example). We find +++ the target of the coming instruction and breakpoint it. */ +++ +++std::vector +++loongarch_software_single_step (struct regcache *regcache) +++{ +++ struct gdbarch *gdbarch = regcache->arch (); +++ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); +++ CORE_ADDR pc = regcache_read_pc (regcache); +++ std::vector next_pcs = +++ loongarch_deal_with_atomic_sequence (regcache, pc); +++ +++ if (!next_pcs.empty ()) +++ return next_pcs; +++ +++ insn_t insn = loongarch_fetch_instruction (pc, NULL); +++ size_t insnlen = loongarch_insn_length (insn); +++ CORE_ADDR next = pc + insnlen; +++ +++ if ((insn & 0xffff8000) == 0x002b0000 && tdep->syscall_next_pc) +++ { +++ CORE_ADDR syscall_next = tdep->syscall_next_pc (get_current_frame ()); +++ if (syscall_next != -1) +++ { +++ if (loongarch_debug) +++ fprintf_unfiltered (gdb_stdlog, +++"PC: %s Syscall found. Next pc is %s.\n", +++paddress (gdbarch, pc), paddress (gdbarch, syscall_next)); +++ return {syscall_next}; +++ } +++ } +++ +++ if (loongarch_insn_is_branch (insn)) +++ { +++ CORE_ADDR branch_tgt = loongarch_next_pc_if_branch (regcache, pc, insn); +++ if (loongarch_debug) +++ fprintf_unfiltered (gdb_stdlog, +++"PC: %s Next pc is %s if branch, %s for non-branch.\n", +++paddress (gdbarch, pc), paddress (gdbarch, branch_tgt), paddress (gdbarch, next)); +++ return {next, branch_tgt}; +++ } +++ else +++ { +++ if (loongarch_debug) +++ fprintf_unfiltered (gdb_stdlog, +++"PC: %s Next pc is %s.\n", +++paddress (gdbarch, pc), paddress (gdbarch, next)); +++ return {next}; +++ } +++} +++ +++/* Callback function for user_reg_add. */ +++ +++static struct value * +++value_of_loongarch_user_reg (struct frame_info *frame, const void *baton) +++{ +++ return value_of_register ((long long) baton, frame); +++} +++ +++/* Implement the register_name gdbarch method. */ +++ +++static const char * +++loongarch_register_name (struct gdbarch *gdbarch, int regnum) +++{ +++ auto regs = &gdbarch_tdep (gdbarch)->regs; +++ +++ if (0 <= regs->r +++ && regs->r <= regnum +++ && regnum < regs->r + 32) +++ switch (gdbarch_tdep (gdbarch)->ef_abi) +++ { +++ case EF_LARCH_ABI_LP64: +++ return loongarch_r_lp64_name[regnum - regs->r] + 1; +++ } +++ else if (0 <= regs->f +++ && regs->f <= regnum +++ && regnum < regs->f + 32) +++ switch (gdbarch_tdep (gdbarch)->ef_abi) +++ { +++ case EF_LARCH_ABI_LP64: +++ return loongarch_f_lp64_name[regnum - regs->f] + 1; +++ } +++ return tdesc_register_name (gdbarch, regnum); +++} +++ +++/* Analyze the function prologue from START_PC to LIMIT_PC. Builds +++ the associated FRAME_CACHE if not null. +++ Return the address of the first instruction past the prologue. */ +++ +++static CORE_ADDR +++loongarch_scan_prologue (struct gdbarch *gdbarch, +++ CORE_ADDR start_pc, CORE_ADDR limit_pc, +++ struct frame_info *this_frame, +++ struct trad_frame_cache *this_cache) +++{ +++ /* 关键问题:我们分析callee的prologue而推断caller的保存寄存器被store在相对于 +++ callee的CFA的偏移量,但在函数执行中途我们不好拿到CFA的值,这是回溯的障碍。 +++ 另外,黄沛给出了Power的ABI作参考,callee在维护调用栈时保持栈顶的两个地址 +++ 恒为caller的返回地址和栈顶。在这里就不用analyze prologue了。但我们的指令集 +++ 看起来还做不到这一点。 +++ +++ 在这里,我们约定 +++ a. CFA(canonical frame address from dwarf2)的值为caller调用callee那一瞬间 +++ $sp的值,即See MIPS run中的“$sp on entry”。这是因为分析prologue是按照控制 +++ 流走向的,这样使得分析更加自然。 +++ b. 定义frame pointer为函数正文执行期间保持不变的,且存储有和CFA有常数 +++ 偏移量的值的寄存器。lp64中的$fp便是这个用途,但考虑到二进制翻译会有寄存器 +++ 映射,frame pointer还真不一定是$fp。对于栈帧不变的函数,$sp就是 +++ frame pointer。 +++ +++ 那么, +++ a. 如果有一个$fp($r22)是$sp($r3)附加偏移量得到的。一旦$r22确定,在整个 +++ 函数执行期间不会变化。对于栈帧可变的函数这很重要。由此,根据callee的$fp +++ 可以反推进入callee时$sp的值,由此就得到了CFA。 +++ b. 如果没有$fp被确定,那么我们认为在prologue中,$sp被调整后,其在函数执行 +++ 期间不会变化,由此我们就知道了CFA。这是栈帧不变的函数。 +++ c. 上述约定尽量在-O0下生效,不过说到底也只是个启发式做法罢了。指令调度会 +++ 使prologue没那么工整;shrink-wrapping会弱化prologue的概念;手写汇编更是可 +++ 以自由发挥,这使得分析极其困难,我们也点到为止。 +++ +++ 那么prologue分析分为两部分, +++ 1. 求出callee的frame pointer,及frame pointer和CFA的偏移量以求出CFA。 +++ 2. 求出来the offset based on CFA storing the register of caller */ +++ +++ auto regs = &gdbarch_tdep (gdbarch)->regs; +++ int rlen_is_64b = (loongarch_rlen (gdbarch) == 64); +++ +++ CORE_ADDR cur_pc, prologue_end = 0; +++ insn_t insn; +++ size_t insnlen; +++ +++ int sp = regs->sp - regs->r; +++ +++ int fp = sp;/* frame pointer */ +++ long frame_offset = 0; +++ int non_prologue_insns = 0; +++ int cfa_unknown = 0; +++ +++ /* try to trace li */ +++ int64_t r_value[32] = {0}; +++ int r_value_known[32] = {1, 0}; +++ +++ long r_cfa_offset[32] = {0}; +++ int r_cfa_offset_p[32] = {0}; +++ +++ long f_cfa_offset[32] = {0}; +++ int f_cfa_offset_p[32] = {0}; +++ +++ if (start_pc + 80 < limit_pc) +++ limit_pc = start_pc + 80; +++ +++ for (cur_pc = start_pc; cur_pc < limit_pc; cur_pc += insnlen) +++ { +++ int rd, rj, rk; +++ int64_t si12, si20, si14; +++ +++ insn = loongarch_fetch_instruction (cur_pc, NULL); +++ insnlen = loongarch_insn_length (insn); +++ +++ rd = loongarch_decode_imm ("0:5", insn, 0); +++ rj = loongarch_decode_imm ("5:5", insn, 0); +++ rk = loongarch_decode_imm ("10:5", insn, 0); +++ si12 = loongarch_decode_imm ("10:12", insn, 1); +++ si20 = loongarch_decode_imm ("5:20", insn, 1); +++ si14 = loongarch_decode_imm ("10:14<<2", insn, 1); +++ +++ if ((((insn & 0xffc00000) == 0x02800000 /* addi.w fp,fp,si12 */ +++ && !rlen_is_64b) +++ || ((insn & 0xffc00000) == 0x02c00000 /* addi.d fp,fp,si12 */ +++ && rlen_is_64b)) +++ && rd == fp && rj == fp) +++ { +++ if (si12 < 0) +++ frame_offset -= si12; +++ else +++ /* Exit loop if a positive stack adjustment is found, which +++ usually means that the stack cleanup code in the function +++ epilogue is reached. */ +++ break; +++ prologue_end = cur_pc + insnlen; +++ } +++ else if ((((insn & 0xffc00000) == 0x29800000 /* st.w rd,fp,si12 */ +++ && !rlen_is_64b) +++ || ((insn & 0xffc00000) == 0x29c00000 /* st.d rd,fp,si12 */ +++ && rlen_is_64b)) +++ && rj == fp) +++ { +++ if (!r_cfa_offset_p[rd] && !r_value_known[rd]) +++ r_cfa_offset[rd] = si12 - frame_offset, r_cfa_offset_p[rd] = 1; +++ prologue_end = cur_pc + insnlen; +++ } +++ else if ((((insn & 0xff000000) == 0x25000000 /* stptr.w rd,fp,si14 */ +++ && !rlen_is_64b) +++ || ((insn & 0xff000000) == 0x27000000 /* stptr.d rd,fp,si14 */ +++ && rlen_is_64b)) +++ && rj == fp) +++ { +++ if (!r_cfa_offset_p[rd] && !r_value_known[rd]) +++ r_cfa_offset[rd] = si14 - frame_offset, r_cfa_offset_p[rd] = 1; +++ prologue_end = cur_pc + insnlen; +++ } +++ else if (((insn & 0xffc00000) == 0x2b400000 /* fst.s fd,fp,si12 */ +++ || (insn & 0xffc00000) == 0x2bc00000) /* fst.d fd,fp,si12 */ +++ && rj == fp) +++ { +++ if (!f_cfa_offset_p[rd]) +++ f_cfa_offset[rd] = si12 - frame_offset, f_cfa_offset_p[rd] = 1; +++ } +++ else if ((((insn & 0xffff8000) == 0x00110000 /* sub.w fp,fp,rk */ +++ && !rlen_is_64b) +++ || ((insn & 0xffff8000) == 0x00118000 /* sub.d fp,fp,rk */ +++ && rlen_is_64b)) +++ && rd == fp && rj == fp) +++ { +++ if (r_value_known[rk]) +++ { +++ frame_offset += r_value[rk]; +++ prologue_end = cur_pc + insnlen; +++ } +++ else +++ cfa_unknown = 1; +++ } +++ else if ((insn & 0xffff8000) == 0x00150000 /* or rd,fp,$r0 */ +++ && rj == fp && rk == 0) +++ { +++ fp = rd; +++ prologue_end = cur_pc + insnlen; +++ } +++ else if ((insn & 0xffc00000) == 0x02800000) /* addi.w rd,rj,si12 */ +++ { +++ if (r_value_known[rj] && rd != 0) +++ r_value[rd] = (int32_t) (r_value[rj] + si12), r_value_known[rd] = 1; +++ } +++ else if ((insn & 0xffc00000) == 0x03800000) /* ori rd,rj,si12 */ +++ { +++ if (r_value_known[rj] && rd != 0) +++ r_value[rd] = r_value[rj] | (si12 & 0xfff) , r_value_known[rd] = 1; +++ } +++ else if ((insn & 0xfe000000) == 0x14000000) /* lu12i.w rd,si20 */ +++ { +++ if (rd != 0) +++ r_value[rd] = si20 << 12, r_value_known[rd] = 1; +++ } +++ else if ((insn & 0xfe000000) == 0x16000000) /* lu32i.d rd,si20 */ +++ { +++ if (r_value_known[rd] && rd != 0) +++ r_value[rd] = (r_value[rd] & 0xffffffff) | (si20 << 32) +++ , r_value_known[rd] = 1; +++ } +++ else if ((insn & 0xffc00000) == 0x03000000) /* lu52i.d rd,rj,si12 */ +++ { +++ if (r_value_known[rj] && rd != 0) +++ r_value[rd] = (r_value[rj] & 0xfffffffffffff) | (si12 << 52) +++ , r_value_known[rd] = 1; +++ } +++ else if (loongarch_insn_is_branch (insn)) +++ break;/* shrink-wrap or end of prologue in a basic block */ +++ else +++ non_prologue_insns++; +++ +++ if (5 < non_prologue_insns) /* 4 INSNs for 'la' and one for some other */ +++ break; +++ } +++ +++ if (loongarch_debug) +++ { +++ const char *fun_name; +++ find_pc_partial_function (start_pc, &fun_name, NULL, NULL); +++ fprintf_unfiltered (gdb_stdlog, +++"Prologue Analyze: -- Start -- Callee [%s] %s\n", +++fun_name ? fun_name : "", paddress (gdbarch, start_pc)); +++ } +++ +++ do +++ { +++ int i; +++ CORE_ADDR cfa = -1, ret = -1; +++ +++ if (!(this_frame && this_cache)) +++ break; +++ +++ if (!cfa_unknown) +++ { +++ try +++ { +++ cfa = get_frame_register_signed +++ (this_frame, regs->r + fp) + frame_offset; +++ } +++ catch (const gdb_exception_error &ex) +++ +++ { +++ cfa_unknown = 1; +++ } +++ if (loongarch_debug) +++ fprintf_unfiltered (gdb_stdlog, +++"Prologue Analyze: CFA is (frame pointer $%s + 0x%lx) = %s\n", +++gdbarch_register_name (gdbarch, regs->r + fp), +++(long)frame_offset, cfa_unknown ? "" : paddress (gdbarch, cfa)); +++ } +++ else +++ if (loongarch_debug) +++ fprintf_unfiltered (gdb_stdlog, +++"Prologue Analyze: Unknown stack frame size, so can't get known CFA\n"); +++ +++ if (r_cfa_offset_p[1] && !cfa_unknown) +++ { +++ CORE_ADDR ret_saved = cfa + r_cfa_offset[1]; +++ trad_frame_set_reg_addr +++ (this_cache, gdbarch_pc_regnum (gdbarch), ret_saved); +++ if (loongarch_debug) +++ fprintf_unfiltered (gdb_stdlog, +++"Prologue Analyze: Return addr saved in (CFA - 0x%lx) = %s\n", +++-r_cfa_offset[1], paddress (gdbarch, ret_saved)); +++ } +++ else if (r_cfa_offset_p[1] /* && cfa_unknown */) +++ { +++ if (loongarch_debug) +++ fprintf_unfiltered (gdb_stdlog, +++"Prologue Analyze: Return addr saved in (CFA - 0x%lx), but CFA is unknown\n", +++-r_cfa_offset[1]); +++ } +++ else +++ { +++ trad_frame_set_reg_realreg +++ (this_cache, gdbarch_pc_regnum (gdbarch), regs->r + 1); +++ if (loongarch_debug) +++ fprintf_unfiltered (gdb_stdlog, +++"Prologue Analyze: No found $r1 pushed in stack. Return addr saved in $r1\n"); +++ } +++ +++ if (cfa_unknown) +++ { +++ trad_frame_set_this_base (this_cache, -1); +++ break; +++ } +++ +++ /* 在这里认为callee的CFA是caller的$sp的值。真实情况不一定如此。但在分析 +++ caller的prologue时, +++ 如果发现caller的frame pointer不为$sp,会unwind备份在callee frame中的 +++ frame pointer,此时$sp的值也不重要了; +++ 如果发现caller的frame pointer为$sp,那么$sp的值就是这个CFA */ +++ trad_frame_set_reg_value +++ (this_cache, gdbarch_sp_regnum (gdbarch), (LONGEST) cfa); +++ trad_frame_set_this_base (this_cache, cfa); +++ +++ if (loongarch_debug) +++ fprintf_unfiltered (gdb_stdlog, +++"Prologue Analyze: Where caller's registers saved as follow:\n"); +++ +++ for (i = 0; i < 32; i++) +++ if (r_cfa_offset_p[i] && i != 1) +++ { +++ trad_frame_set_reg_addr +++ (this_cache, regs->r + i, cfa + r_cfa_offset[i]); +++ if (loongarch_debug) +++ fprintf_unfiltered (gdb_stdlog, +++"Prologue Analyze: $%s: saved in (CFA - 0x%lx) = %s\n", +++gdbarch_register_name (gdbarch, regs->r + i), -r_cfa_offset[i], +++paddress (gdbarch, cfa + r_cfa_offset[i])); +++ } +++ +++ if (regs->f <= 0) +++ for (i = 0; i < 32; i++) +++ { +++ if (f_cfa_offset_p[i]) +++ trad_frame_set_reg_addr +++ (this_cache, regs->f + i, cfa + f_cfa_offset[i]); +++ if (loongarch_debug) +++ fprintf_unfiltered (gdb_stdlog, +++"Prologue Analyze: $%s: saved in (CFA - 0x%lx) = %s\n", +++gdbarch_register_name (gdbarch, regs->f + i), -f_cfa_offset[i], +++paddress (gdbarch, cfa + f_cfa_offset[i])); +++ } +++ } +++ while (0); +++ +++ if (loongarch_debug) +++ fprintf_unfiltered (gdb_stdlog, +++"Prologue Analyze: -- End -- %s\n", paddress (gdbarch, cur_pc)); +++ +++ return prologue_end ? prologue_end : cur_pc; +++} +++ +++ +++/* Implement the loongarch_skip_prologue gdbarch method. */ +++ +++/* To skip prologues, I use this predicate. Returns either PC itself +++ if the code at PC does not look like a function prologue; otherwise +++ returns an address that (if we're lucky) follows the prologue. If +++ LENIENT, then we must skip everything which is involved in setting +++ up the frame (it's OK to skip more, just so long as we don't skip +++ anything which might clobber the registers which are being saved. +++ We must skip more in the case where part of the prologue is in the +++ delay slot of a non-prologue instruction). */ +++ +++static CORE_ADDR +++loongarch_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc) +++{ +++ CORE_ADDR limit_pc; +++ CORE_ADDR func_addr; +++ +++ /* 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 + 100; /* Magic. */ +++ +++ return loongarch_scan_prologue (gdbarch, pc, limit_pc, NULL, NULL); +++} +++ +++ +++/* Adjust the address downward (direction of stack growth) so that it +++ is correctly aligned for a new stack frame. */ +++static CORE_ADDR +++loongarch_frame_align (struct gdbarch *gdbarch, CORE_ADDR addr) +++{ +++ return align_down (addr, 16); +++} +++ +++ +++/* Implement the unwind_pc gdbarch method. */ +++ +++static CORE_ADDR +++loongarch_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame) +++{ +++ return frame_unwind_register_signed +++ (next_frame, gdbarch_pc_regnum (gdbarch)); +++} +++ +++ +++/* Implement the unwind_sp gdbarch method. */ +++ +++static CORE_ADDR +++loongarch_unwind_sp (struct gdbarch *gdbarch, struct frame_info *next_frame) +++{ +++ return frame_unwind_register_signed +++ (next_frame, gdbarch_sp_regnum (gdbarch)); +++} +++ +++ +++/* Implement the dummy_id gdbarch method. */ +++ +++static struct frame_id +++loongarch_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame) +++{ +++ return frame_id_build +++ (get_frame_register_signed (this_frame, +++ gdbarch_sp_regnum (gdbarch)), +++ get_frame_pc (this_frame)); +++} +++ +++/* Generate, or return the cached frame cache for the RiscV frame +++ unwinder. */ +++ +++static struct trad_frame_cache * +++loongarch_frame_cache (struct frame_info *this_frame, void **this_cache) +++{ +++ struct gdbarch *gdbarch = get_frame_arch (this_frame); +++ struct trad_frame_cache *cache; +++ CORE_ADDR pc, start_addr, stack_addr; +++ +++ if (*this_cache != NULL) +++ return (struct trad_frame_cache *) *this_cache; +++ cache = trad_frame_cache_zalloc (this_frame); +++ *this_cache = cache; +++ +++ /* 这里的情况是,已知callee中各寄存器的值(包括PC),分析callee的prologue +++ 来推测caller中各寄存器备份在callee栈帧中的位置。 */ +++ +++/* 我们先拿到callee的PC */ +++ pc = get_frame_address_in_block (this_frame); +++ if (find_pc_partial_function (pc, NULL, &start_addr, NULL)) +++ { +++/* find_pc_partial_function会从debug信息拿到函数开头,如果成功了,那啥也 +++ 不说了,开始scan_prologue */ +++ loongarch_scan_prologue (gdbarch, start_addr, pc, this_frame, cache); +++ stack_addr = trad_frame_get_this_base (cache); +++ trad_frame_set_id (cache, stack_addr == -1 ? +++ frame_id_build_unavailable_stack (start_addr) : +++ frame_id_build (stack_addr, start_addr)); +++ } +++ else +++ { +++/* 如果失败了,可能有三种情况 +++ 1. PC在某个trampoline上。那应该有某个struct tramp_frame的sniffer的匹配 +++ 优先级比这个通用的struct frame_unwind高。 +++ 2. PC在某个函数中,可能在elf文件中但没debug信息;也可能是自修改代码。不考虑 +++ 3. PC非法,反正要么已经发生段错误了;要么迟早发生段错误。不过这种的也要 +++ 看情况,比如基本块没设计好,PC飞了,我们根本没任何线索搞backtrace。 +++ 我们在这里考虑的情况唯一情况是进行了失败的绝对跳转的函数调用,这样的话 +++ caller的寄存器都在,而caller的地址就在ra中。 */ +++ auto regs = &gdbarch_tdep (gdbarch)->regs; +++ /* 注意:我们认为caller的$ra是unknown的。原因是,下次unwind时的 +++ find_pc_partial_function失效后(即callee的$ra不在某个带debug信息的 +++ 函数内),认为caller的caller的PC为caller的$ra。如果仍然认为caller的$ra +++ 是callee的$ra,这个失效的PC值会让unwind无法停下来了。 */ +++ trad_frame_set_reg_realreg (cache, regs->ra, -2/* TF_REG_UNKNOWN */); +++ trad_frame_set_reg_realreg +++ (cache, gdbarch_pc_regnum (gdbarch), regs->ra); +++ +++ trad_frame_set_id (cache, frame_id_build_unavailable_stack (pc)); +++ } +++ return cache; +++} +++ +++ +++/* Implement the this_id callback for RiscV frame unwinder. */ +++ +++static void +++loongarch_frame_this_id (struct frame_info *this_frame, +++ void **prologue_cache, +++ struct frame_id *this_id) +++{ +++ struct trad_frame_cache *info; +++ +++ info = loongarch_frame_cache (this_frame, prologue_cache); +++ trad_frame_get_id (info, this_id); +++} +++ +++ +++/* Implement the prev_register callback for RiscV frame unwinder. */ +++ +++static struct value * +++loongarch_frame_prev_register (struct frame_info *this_frame, +++ void **prologue_cache, +++ int regnum) +++{ +++ struct trad_frame_cache *info; +++ +++ info = loongarch_frame_cache (this_frame, prologue_cache); +++ return trad_frame_get_register (info, this_frame, regnum); +++} +++ +++ +++/* Structure defining the RiscV normal frame unwind functions. Since we +++ are the fallback unwinder (DWARF unwinder is used first), we use the +++ default frame sniffer, which always accepts the frame. */ +++ +++static const struct frame_unwind loongarch_frame_unwind = +++{ +++ /*.type =*/ NORMAL_FRAME, +++ /*.stop_reason =*/ default_frame_unwind_stop_reason, +++ /*.this_id =*/ loongarch_frame_this_id, +++ /*.prev_register =*/ loongarch_frame_prev_register, +++ /*.unwind_data =*/ NULL, +++ /*.sniffer =*/ default_frame_sniffer, +++ /*.dealloc_cache =*/ NULL, +++ /*.prev_arch =*/ NULL, +++}; +++ +++struct small_struct_data_t +++{ +++ char fixed_member; +++ char float_member; +++ bool first_member_is_float; +++}; +++ +++static void +++pass_on_reg (struct regcache *regcache, int regno, const gdb_byte *val, +++ int len) +++{ +++ gdb_byte reg[32]; +++ memset (reg, 0, sizeof (reg)); +++ memcpy (reg, val, len); +++ regcache->cooked_write (regno, reg); +++} +++ +++ +++static void +++get_struct_member (struct type *tp, small_struct_data_t *small_struct) +++{ +++ for (int i = 0; i < TYPE_NFIELDS(tp); i++) +++ { +++ field fd = tp->field (i); +++ struct type *t = fd.type(); +++ +++ /* Call check_typedef(TYPE_TARGET_TYPE (TYPE)) on our type to make +++ sure that, if TYPE is a TYPE_CODE_TYPEDEF, its TYPE is set to +++ the target type instead of TYPE_CODE_TYPEDEF. */ +++ if (TYPE_CODE(t) == TYPE_CODE_TYPEDEF) +++ t = check_typedef (TYPE_TARGET_TYPE (t)); +++ +++ switch (TYPE_CODE(t)) +++ { +++ case TYPE_CODE_STRUCT: +++ get_struct_member (t, small_struct); +++ break; +++ case TYPE_CODE_COMPLEX: +++ small_struct->float_member += 2; +++ break; +++ case TYPE_CODE_FLT: +++ small_struct->float_member++; +++ break; +++ default: +++ if (small_struct->float_member > 0 && small_struct->fixed_member == 0) +++ small_struct->first_member_is_float = true; +++ small_struct->fixed_member++; +++ break; +++ } +++ } +++} +++ +++ +++/* 为了做mips的汇编级兼容,LP64和n64的传参方法是相同的 */ +++/* N32/N64 ABI stuff. */ +++ +++/* Implement the push dummy call gdbarch callback. */ +++ +++static CORE_ADDR +++loongarch_xlp32lp64_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 struct_return, CORE_ADDR struct_addr) +++{ +++ const size_t rlen = loongarch_rlen (gdbarch) / 8; +++ size_t i; +++ auto regs = &gdbarch_tdep (gdbarch)->regs; +++ /* 1. We find out the size of space to settle actual args */ +++ size_t Narg_slots = 0; +++ if (struct_return) +++ Narg_slots++; +++ for (i = 0; i < nargs; i++) +++ { +++ struct value *arg = args[i]; +++ struct type *arg_type = check_typedef (value_type (arg)); +++ size_t len = TYPE_LENGTH (arg_type); +++ size_t align = type_align (arg_type); +++ enum type_code typecode = TYPE_CODE (arg_type); +++ +++ gdb_assert (0 < align); +++ if (typecode == TYPE_CODE_COMPLEX && len == 8 +++ && TYPE_CODE (check_typedef (TYPE_TARGET_TYPE (arg_type))) +++ == TYPE_CODE_FLT) +++ /* For _Complex float, sometimes we need two float argument registers +++ to fit its real and img. */ +++ Narg_slots += 2; +++ else +++ { +++ Narg_slots = align_up (Narg_slots, (align + rlen - 1) / rlen); +++ Narg_slots += (len + rlen - 1) / rlen; +++ } +++ } +++ +++ /* 2. Set all actual arguments here */ +++ struct type *func_type = check_typedef (value_type (function)); +++ gdb_byte raw_args[Narg_slots * rlen]; +++ int flt_num = 0; +++ Narg_slots = 0; +++ if (struct_return) +++ store_signed_integer (raw_args + Narg_slots * rlen, rlen, BFD_ENDIAN_LITTLE, struct_addr) +++ , Narg_slots++; +++ +++ for (i = 0; i < nargs; i++) +++ { +++ struct value *arg = args[i]; +++ struct type *arg_type = check_typedef (value_type (arg)); +++ size_t len = TYPE_LENGTH (arg_type); +++ size_t align = type_align (arg_type); +++ enum type_code typecode = TYPE_CODE (arg_type); +++ const gdb_byte *val = value_contents (arg); +++ int is_var = TYPE_VARARGS (func_type) && TYPE_NFIELDS (func_type) <= i; +++ small_struct_data_t small_struct = {0, 0, false}; +++ +++ if (((typecode == TYPE_CODE_INT && TYPE_UNSIGNED (arg_type)) +++ || typecode == TYPE_CODE_ENUM) && len <= rlen) +++ { +++ /* For unsigned scalar type in a register */ +++ ULONGEST i = extract_unsigned_integer (val, len, BFD_ENDIAN_LITTLE); +++ store_unsigned_integer (raw_args + Narg_slots * rlen, rlen, BFD_ENDIAN_LITTLE, i); +++ Narg_slots++; +++ } +++ else if ((typecode == TYPE_CODE_INT || typecode == TYPE_CODE_PTR) && len <= rlen) +++ { +++ /* For signed scalar type in a register */ +++ LONGEST i = extract_signed_integer (val, len, BFD_ENDIAN_LITTLE); +++ store_signed_integer (raw_args + Narg_slots * rlen, rlen, BFD_ENDIAN_LITTLE, i); +++ Narg_slots++; +++ } +++ else if (typecode == TYPE_CODE_FLT) +++ { +++ /* long double */ +++ if (len > rlen ) +++ { +++ if ( Narg_slots >= 8) +++ Narg_slots = align_up (Narg_slots, (align + rlen - 1) / rlen); +++ memcpy (raw_args + Narg_slots * rlen, val, rlen); +++ memcpy (raw_args + (Narg_slots + 1) * rlen, val + rlen, len - rlen); +++ Narg_slots += 2; +++ } +++ /* float、 double */ +++ else +++ { +++ if (flt_num < 8) +++ { +++ pass_on_reg (regcache, regs->f/* $fa0 */ + flt_num, val, rlen); +++ flt_num++; +++ } +++ else +++ { +++ memcpy (raw_args + Narg_slots * rlen, val, len); +++ Narg_slots += (len + rlen - 1) / rlen; +++ } +++ } +++ } +++ else if (typecode == TYPE_CODE_STRUCT) +++ { +++ get_struct_member (arg_type, &small_struct); +++ /* It’s passed by reference and are replaced in the argument list with the address. +++ If there is an available GAR, the reference is passed in the GAR, and passed on +++ the stack if no GAR is available */ +++ if (len > rlen * 2) +++ { +++ /* Address on register, data on stack. */ +++ sp = align_down (sp - len, 16); +++ write_memory (sp, val, len); +++ memcpy (raw_args + Narg_slots * rlen, (const gdb_byte *) &sp, rlen); +++ Narg_slots += 1; +++ } +++ else if (rlen < len && len <= 2 * rlen) +++ { +++ /* Only fixed-point members, the argument is passed in a pair of available GAR, +++ with the low-order bits in the lower-numbered GAR and the high-order bits in +++ the higher-numbered GAR. If only one GAR is available, the low-order bits are +++ in the GAR and the high-order bits are on the stack, and passed on the stack +++ if no GAR is available. */ +++ if (small_struct.fixed_member > 0 && small_struct.float_member == 0) +++ { +++ memcpy (raw_args + Narg_slots * rlen, val, rlen); +++ memcpy (raw_args + (Narg_slots + 1) * rlen, val + rlen, len - rlen); +++ Narg_slots += 2; +++ } +++ /* Only floating-point members. */ +++ else if (small_struct.fixed_member == 0 && small_struct.float_member > 0 ) +++ { +++ /* The structure has one long double member or one double member and two +++ adjacent float members or 3-4 float members. The argument is passed +++ in a pair of available GAR, with the low-order bits in the lower-numbered +++ GAR and the high-order bits in the higher-numbered GAR. If only one +++ GAR is available, the low-order bits are in the GAR and the high-order +++ bits are on the stack, and passed on the stack if no GAR is available. */ +++ if (small_struct.float_member == 1 || small_struct.float_member > 2 ) +++ { +++ memcpy (raw_args + Narg_slots * rlen, val, rlen); +++ memcpy (raw_args + (Narg_slots + 1) * rlen, val + rlen, len - rlen); +++ Narg_slots += 2; +++ } +++ /* The structure with two double members is passed in a pair of available +++ FARs. If no a pair of available FARs, it’s passed in GARs. If only one +++ GAR is available, the low-order bits are in the GAR and the high-order +++ bits are on the stack, and passed on the stack if no GAR is available, +++ A structure with one double member and one float member is same. */ +++ else if (small_struct.float_member == 2) +++ { +++ if (flt_num < 7) +++ { +++ pass_on_reg (regcache, regs->f + flt_num++, val, rlen); +++ pass_on_reg (regcache, regs->f + flt_num++, val + rlen, len - rlen); +++ } +++ else +++ { +++ memcpy (raw_args + Narg_slots * rlen, val, rlen); +++ memcpy (raw_args + (Narg_slots + 1) * rlen, val + rlen, len - rlen); +++ Narg_slots += 2; +++ } +++ } +++ } +++ /* Both fixed-point and floating-point members. */ +++ else if (small_struct.fixed_member > 0 && small_struct.float_member > 0 ) +++ { +++ /* The structure has one floating-point member and one fixed-point member. +++ If one FAR and one GAR are available, the floating-point member of the +++ structure is passed in the FAR, and the integer member of the structure +++ is passed in the GAR; If no floating-point registers but two GARs are +++ available, it’s passed in the two GARs; If only one GAR is available, +++ the low-order bits are in the GAR and the high-order bits are on the +++ stack; And it’s passed on the stack if no GAR is available. */ +++ if (small_struct.fixed_member == 1 && small_struct.float_member == 1) +++ { +++ if (flt_num < 8 && Narg_slots < 8) +++ { +++ if (small_struct.first_member_is_float) +++ { +++ pass_on_reg (regcache, regs->f + flt_num++, val, rlen); +++ memcpy (raw_args + Narg_slots * rlen, val + rlen, len - rlen); +++ Narg_slots ++; +++ } +++ else +++ { +++ memcpy (raw_args + Narg_slots * rlen, val, rlen); +++ Narg_slots ++; +++ pass_on_reg (regcache, regs->f + flt_num++, val + rlen, len - rlen); +++ } +++ } +++ else +++ { +++ memcpy (raw_args + Narg_slots * rlen, val, rlen); +++ memcpy (raw_args + (Narg_slots + 1) * rlen, val + rlen, len - rlen); +++ Narg_slots += 2; +++ } +++ } +++ /* Others, the argument is passed in a pair of available GAR, with the +++ low-order bits in the lower-numbered GAR and the high-order bits in +++ the higher-numbered GAR. If only one GAR is available, the low-order +++ bits are in the GAR and the high-order bits are on the stack, and +++ passed on the stack if no GAR is available. */ +++ else +++ { +++ memcpy (raw_args + Narg_slots * rlen, val, rlen); +++ memcpy (raw_args + (Narg_slots + 1) * rlen, val + rlen, len - rlen); +++ Narg_slots += 2; +++ } +++ } +++ } +++ /* len < = rlen */ +++ else +++ { +++ /* The structure has only fixed-point members. If there is an available GAR, +++ the structure is passed through the GAR by value passing; If no GAR is +++ available, it’s passed on the stack. */ +++ if (small_struct.fixed_member > 0 && small_struct.float_member == 0) +++ { +++ memcpy (raw_args + Narg_slots * rlen, val, len); +++ Narg_slots ++; +++ } +++ /* The structure has only floating-point members. */ +++ else if (small_struct.fixed_member == 0 && small_struct.float_member > 0) +++ { +++ /* One floating-point member. The argument is passed in a FAR; If no FAR +++ is available, the value is passed in a GAR; if no GAR is available, the +++ value is passed on the stack. */ +++ if (small_struct.float_member == 1) +++ { +++ if (flt_num < 8) +++ { +++ pass_on_reg (regcache, regs->f + flt_num++, val, rlen); +++ } +++ else +++ { +++ memcpy (raw_args + Narg_slots * rlen, val, len); +++ Narg_slots ++; +++ } +++ } +++ /* Two floating-point members. The argument is passed in a pair of available +++ FAR, with the low-order float member bits in the lower-numbered FAR and +++ the high-order float member bits in the higher-numbered FAR. If the number +++ of available FAR is less than 2, it’s passed in a GAR, and passed on the +++ stack if no GAR is available. */ +++ else if (small_struct.float_member == 2) +++ { +++ if (flt_num < 7) +++ { +++ pass_on_reg (regcache, regs->f + flt_num++, val, len/2); +++ pass_on_reg (regcache, regs->f + flt_num++, val + len/2, len/2); +++ } +++ else +++ { +++ memcpy (raw_args + Narg_slots * rlen, val, len); +++ Narg_slots ++; +++ } +++ } +++ } +++ /* The structure has both fixed-point and floating-point members, +++ i.e. the structure has one float member and… */ +++ else if (small_struct.fixed_member > 0 && small_struct.float_member == 1) +++ { +++ /* Multiple fixed-point members. If there are available GAR, the structure +++ is passed in a GAR, and passed on the stack if no GAR is available. */ +++ if (small_struct.fixed_member > 1) +++ { +++ memcpy (raw_args + Narg_slots * rlen, val, len); +++ Narg_slots ++; +++ } +++ /* Only one fixed-point member. If one FAR and one GAR are available, the +++ floating-point member of the structure is passed in the FAR, and the integer +++ member of the structure is passed in the GAR; If no floating-point register +++ but one GAR is available, it’s passed in GAR; If no GAR is available, it’s +++ passed on the stack. */ +++ else if (small_struct.fixed_member == 1) +++ { +++ if (flt_num < 8 && Narg_slots < 8) +++ { +++ if (small_struct.first_member_is_float) +++ { +++ pass_on_reg (regcache, regs->f + flt_num++, val, len/2); +++ memcpy (raw_args + Narg_slots * rlen, val + len/2, len/2); +++ Narg_slots ++; +++ } +++ else +++ { +++ memcpy (raw_args + Narg_slots * rlen, val, len/2); +++ Narg_slots ++; +++ pass_on_reg (regcache, regs->f + flt_num++, val + len/2, len/2); +++ } +++ } +++ else +++ { +++ memcpy (raw_args + Narg_slots * rlen, val, len); +++ Narg_slots ++; +++ } +++ } +++ } +++ } +++ } +++ else if (typecode == TYPE_CODE_UNION) +++ { +++ /* The argument is passed in a GAR, or on the stack by value if no GAR is available. */ +++ if (len <= rlen) +++ { +++ memcpy (raw_args + Narg_slots * rlen, val, len); +++ Narg_slots += 1; +++ } +++ /* The argument is passed in a pair of available GAR, with the low-order bits in the +++ lower-numbered GAR and the high-order bits in the higher-numbered GAR. If only one +++ GAR is available, the low-order bits are in the GAR and the high-order bits are on +++ the stack. The arguments are passed on the stack when no GAR is available. */ +++ else if (len > rlen && len <= 2 * rlen) +++ { +++ memcpy (raw_args + Narg_slots * rlen, val, rlen); +++ memcpy (raw_args + (Narg_slots + 1) * rlen, val + rlen, len - rlen); +++ Narg_slots += 2; +++ } +++ /* It’s passed by reference and are replaced in the argument list with the address. +++ If there is an available GAR, the reference is passed in the GAR, and passed on +++ the stack if no GAR is available. */ +++ else +++ { +++ sp = align_down (sp - len, 16); +++ write_memory (sp, val, len); +++ memcpy (raw_args + Narg_slots * rlen, (const gdb_byte *) &sp, rlen); +++ Narg_slots += 1; +++ } +++ } +++ else if (typecode == TYPE_CODE_COMPLEX) +++ { +++ struct type *t_type = check_typedef (TYPE_TARGET_TYPE (arg_type)); +++ int tlen = TYPE_LENGTH (t_type); +++ /* float _Complex */ +++ if (tlen < rlen) +++ { +++ if (flt_num < 7) +++ { +++ pass_on_reg (regcache, regs->f/* $fa0 */ + flt_num++, val, tlen); +++ pass_on_reg (regcache, regs->f/* $fa0 */ + flt_num++, val + tlen, tlen); +++ } +++ else +++ { +++ memcpy (raw_args + Narg_slots * rlen, val, rlen); +++ Narg_slots += 1; +++ } +++ } +++ /* double _Complex */ +++ else if (tlen == rlen) +++ { +++ if (flt_num < 7) +++ { +++ pass_on_reg (regcache, regs->f/* $fa0 */ + flt_num++, val, tlen); +++ pass_on_reg (regcache, regs->f/* $fa0 */ + flt_num++, val + tlen, tlen); +++ } +++ else +++ { +++ memcpy (raw_args + Narg_slots * rlen, val, tlen); +++ memcpy (raw_args + (Narg_slots + 1) * rlen, val + tlen, tlen); +++ Narg_slots += 2; +++ } +++ } +++ /* long double _Complex */ +++ else +++ { +++ /* Address on register, data on stack. */ +++ sp = align_down (sp - len, 16); +++ write_memory (sp, val, len); +++ memcpy (raw_args + Narg_slots * rlen, (const gdb_byte *) &sp, rlen); +++ Narg_slots += 1; +++ } +++ } +++ else +++ { +++ /* Otherwise for bigger actual args, such as +++ '_Complex double long' etc, we memcpy. */ +++ memcpy (raw_args + Narg_slots * rlen, val, len); +++ Narg_slots += (len + rlen - 1) / rlen; +++ } +++ } +++ +++ /* 3. Write in stack and argument registers */ +++ if (8 < Narg_slots) +++ sp -= (Narg_slots - 8) * rlen; +++ sp = align_down (sp, 16); +++ +++ if (8 < Narg_slots) +++ write_memory (sp, raw_args + 8 * rlen, (Narg_slots - 8) * rlen); +++ +++ regcache_cooked_write_signed (regcache, regs->ra, bp_addr); +++ regcache_cooked_write_signed (regcache, regs->sp, sp); +++ for (i = 0; i < (8 < Narg_slots ? 8 : Narg_slots); i++) +++ { +++ pass_on_reg (regcache, regs->r+4/* $a0 */ + i, raw_args + i * rlen, rlen); +++ } +++ +++ return sp; +++} +++ +++static void +++loongarch_xfer_reg_part (struct regcache *regcache, int reg_num, +++ int len, gdb_byte *readbuf, size_t readbuf_off, +++ const gdb_byte *writebuf, size_t writebuf_off) +++{ +++ if (readbuf) +++ regcache->cooked_read_part (reg_num, 0, len, readbuf + readbuf_off); +++ if (writebuf) +++ regcache->cooked_write_part (reg_num, 0, len, writebuf + writebuf_off); +++} +++ +++static enum return_value_convention +++loongarch_xlp32lp64_return_value (struct gdbarch *gdbarch, +++ struct value *function, +++ struct type *type, struct regcache *regcache, +++ gdb_byte *readbuf, const gdb_byte *writebuf) +++{ +++ const size_t rlen = loongarch_rlen (gdbarch) / 8; +++ auto regs = &gdbarch_tdep (gdbarch)->regs; +++ size_t len = TYPE_LENGTH (type); +++ enum type_code typecode = TYPE_CODE (type); +++ int fpu_exist = 0 <= regs->f; +++ int fv = fpu_exist ? regs->f : regs->r + 4; +++ +++ gdb_assert (8 <= sizeof (LONGEST)); +++ +++ gdb_assert (!fpu_exist || register_size (gdbarch, regs->f) == rlen); +++ +++ if (2 * rlen < len) +++ return RETURN_VALUE_STRUCT_CONVENTION; +++ +++ if ((typecode == TYPE_CODE_FLT +++ || (typecode == TYPE_CODE_STRUCT && TYPE_NFIELDS (type) == 1 +++ && TYPE_CODE (check_typedef (type->field (0).type ())) +++ == TYPE_CODE_FLT)) +++ && len <= rlen/* FIXME: May fpu32 on loongarch32 */) +++ /* If $fv0 could fit in. */ +++ loongarch_xfer_reg_part (regcache, fv, len, readbuf, 0, writebuf, 0); +++ else if ((typecode == TYPE_CODE_FLT +++ || (typecode == TYPE_CODE_STRUCT && TYPE_NFIELDS (type) == 1 +++ && TYPE_CODE (check_typedef (type->field (0).type ())) +++ == TYPE_CODE_FLT)) && rlen < len && len <= 2 * rlen) +++ /* For 'long double' on fpu64 or 'double' on fpu32, +++ '$fv0 | $fv1' is that.*/ +++ loongarch_xfer_reg_part (regcache, fv, rlen, readbuf, 0, writebuf, 0) +++ , loongarch_xfer_reg_part +++ (regcache, fv + 1, len - rlen, readbuf, rlen, writebuf, rlen); +++ else if (typecode == TYPE_CODE_STRUCT && TYPE_NFIELDS (type) == 2 +++ && TYPE_CODE (check_typedef (type->field (0).type ())) +++ == TYPE_CODE_FLT +++ && TYPE_CODE (check_typedef (type->field (1).type ())) +++ == TYPE_CODE_FLT) +++ { +++ /* For structure with two float member, +++ $fv0 is the 1st member and $fv1 is the 2nd member */ +++ int off = FIELD_BITPOS (type->field (1)) / TARGET_CHAR_BIT; +++ int len1 = TYPE_LENGTH (check_typedef (type->field (0).type ())); +++ int len2 = TYPE_LENGTH (check_typedef (type->field (1).type ())); +++ loongarch_xfer_reg_part (regcache, fv, len1, readbuf, 0, writebuf, 0); +++ loongarch_xfer_reg_part +++ (regcache, fv + 1, len2, readbuf, off, writebuf, off); +++ } +++ else if (typecode == TYPE_CODE_COMPLEX +++ && TYPE_CODE (check_typedef (TYPE_TARGET_TYPE (type))) +++ == TYPE_CODE_FLT) +++ /* For '_Complex', $fv0 is real and $fv1 is img. */ +++ loongarch_xfer_reg_part (regcache, fv, len / 2, readbuf, 0, writebuf, 0) +++ , loongarch_xfer_reg_part +++ (regcache, fv + 1, len / 2, readbuf, len / 2, writebuf, len / 2); +++ else if (((typecode == TYPE_CODE_INT && TYPE_UNSIGNED (type)) +++ || typecode == TYPE_CODE_ENUM) +++ && len <= rlen) +++ /* For unsigned scalar type, we have zero-extended one in $v0. */ +++ if (writebuf) +++ { +++ gdb_byte buf[rlen]; +++ store_signed_integer (buf, rlen, BFD_ENDIAN_LITTLE, +++ extract_unsigned_integer (writebuf, len, BFD_ENDIAN_LITTLE)); +++ loongarch_xfer_reg_part +++ (regcache, regs->r + 4, rlen, NULL, 0, writebuf, 0); +++ } +++ else +++ loongarch_xfer_reg_part +++ (regcache, regs->r + 4, len, readbuf, 0, NULL, 0); +++ else if (((typecode == TYPE_CODE_INT && !TYPE_UNSIGNED (type)) +++ || typecode == TYPE_CODE_PTR) +++ && len <= rlen) +++ /* For signed scalar type, we have sign-extended one in $v0. */ +++ if (writebuf) +++ { +++ gdb_byte buf[rlen]; +++ store_signed_integer (buf, rlen, BFD_ENDIAN_LITTLE, +++ extract_signed_integer (writebuf, len, BFD_ENDIAN_LITTLE)); +++ loongarch_xfer_reg_part +++ (regcache, regs->r + 4, rlen, NULL, 0, writebuf, 0); +++ } +++ else +++ loongarch_xfer_reg_part +++ (regcache, regs->r + 4, len, readbuf, 0, NULL, 0); +++ else +++ { +++ /* For small structure or int64_t on loongarch32 */ +++ if (len <= rlen) +++ loongarch_xfer_reg_part +++ (regcache, regs->r + 4, len, readbuf, 0, writebuf, 0); +++ else +++ loongarch_xfer_reg_part +++ (regcache, regs->r + 4, rlen, readbuf, 0, writebuf, 0) +++ , loongarch_xfer_reg_part (regcache, regs->r + 5, len - rlen, +++ readbuf, rlen, writebuf, rlen); +++ } +++ +++ return RETURN_VALUE_REGISTER_CONVENTION; +++} +++ +++static int +++loongarch_dwarf2_reg_to_regnum (struct gdbarch *gdbarch, int num) +++{ +++ auto regs = &gdbarch_tdep (gdbarch)->regs; +++ if (0 <= num && num < 32) +++ return regs->r + num; +++ else if (32 <= num && num < 64 && 0 <= regs->f) +++ return regs->f + num - 32; +++ else if (64 <= num && num < 72 && 0 <= regs->fcc) +++ return regs->fcc + num - 64; +++ else +++ return -1; +++} +++ +++static std::string +++loongarch_gcc_target_options (struct gdbarch *gdbarch) +++{ +++ return NULL; +++} +++ +++static int +++loongarch_register_reggroup_p (struct gdbarch *gdbarch, int regnum, +++ struct reggroup *group) +++{ +++ auto regs = &gdbarch_tdep (gdbarch)->regs; +++ +++ if (gdbarch_register_name (gdbarch, regnum) == NULL +++ || *gdbarch_register_name (gdbarch, regnum) == '\0') +++ return 0; +++ +++ int raw_p = regnum < gdbarch_num_regs (gdbarch); +++ +++ if (group == save_reggroup || group == restore_reggroup) +++ return raw_p; +++ if (group == all_reggroup) +++ return 1; +++ +++ /* 重载默认的reggroup_p函数主要是为了自定义info register的寄存器显示。 +++ 默认的reggroup_p对float_reggroup的判断是“register_type是不是浮点”, +++ 我在feature中对浮点寄存器设定的类型是union {float f; double d;}, +++ 因此reggroup_p默认情况下不认为浮点寄存器属于float_reggroup,info float +++ 就不打印浮点寄存器;info vector也是类似。info register默认会打印LBT +++ 寄存器,因为它们属于general_reggroup,但实际上这些寄存器相当特殊。 */ +++ +++ if (group == general_reggroup +++ && (regs->pc == regnum +++ || regs->badvaddr == regnum +++ || (regs->r <= regnum && regnum < regs->r + 32))) +++ return 1; +++ +++ /* Only $rx and $pc in general_reggroup */ +++ if (group == general_reggroup) +++ return 0; +++ +++ if (0 <= regs->f +++ && (regs->fcsr == regnum +++ || (regs->f <= regnum && regnum < regs->f + 32) +++ || (regs->fcc <= regnum && regnum < regs->fcc +8))) +++ return group == float_reggroup; +++ +++ /* Only $fx / $fccx / $fcsr in float_reggroup */ +++ if (group == float_reggroup) +++ return 0; +++ +++ if (0 <= regs->vr && regs->vr <= regnum && regnum < regs->vr + 32) +++ if (group == vector_reggroup) +++ return 1; +++ +++ if (0 <= regs->xr && regs->xr <= regnum && regnum < regs->xr + 32) +++ if (group == vector_reggroup) +++ return 1; +++ +++ int ret = tdesc_register_in_reggroup_p (gdbarch, regnum, group); +++ if (ret != -1) +++ return ret; +++ +++ return default_register_reggroup_p (gdbarch, regnum, group); +++} +++ +++static void +++loongarch_print_all_r_registers (struct gdbarch *gdbarch, struct ui_file *file, +++ struct frame_info *frame) +++{ +++ int i, col; +++ int rlen = loongarch_rlen (gdbarch) / 8; +++ int ncols = rlen == 4 ? 8 : 4; +++ +++ for (i = 0; i < 32; i += ncols) +++ { +++ fprintf_filtered (file, " "); +++ for (col = 0; col < ncols; col++) +++ fprintf_filtered (file, rlen == 8 ? "%17s" : "%9s", +++ gdbarch_register_name (gdbarch, i + col)); +++ +++ fprintf_filtered (file, "\nR%-4d", i); +++ +++ for (col = 0; col < ncols; col++) +++ { +++ const gdb_byte *raw_buffer; +++ struct value *value = get_frame_register_value (frame, i + col); +++ int byte; +++ if (value_optimized_out (value) || !value_entirely_available (value)) +++ fprintf_filtered +++ (file, "%*s", 2 * rlen, rlen == 4 ? "" : ""); +++ else +++ { +++ int byte; +++ const gdb_byte *raw_buffer = value_contents_all (value); +++ for (byte = rlen - 1; 0 <= byte; byte--) +++ fprintf_filtered (file, "%02x", raw_buffer[byte]); +++ } +++ fprintf_filtered (file, " "); +++ } +++ fprintf_filtered (file, "\n"); +++ } +++} +++ +++static void +++loongarch_print_fp_register (struct ui_file *file, struct frame_info *frame, +++ int regnum) +++{ +++ struct gdbarch *gdbarch = get_frame_arch (frame); +++ struct value *value = get_frame_register_value (frame, regnum); +++ const gdb_byte *raw_buffer = value_contents_all (value); +++ struct value_print_options opts; +++ +++ fprintf_filtered (file, "%-5s ", gdbarch_register_name (gdbarch, regnum)); +++ +++ get_formatted_print_options (&opts, 'x'); +++ fprintf_filtered (file, "%s","{f = "); +++ print_scalar_formatted (raw_buffer, +++ builtin_type (gdbarch)->builtin_uint32, +++ &opts, 'w', file); +++ fprintf_filtered (file, ", %s","d = "); +++ print_scalar_formatted (raw_buffer, +++ builtin_type (gdbarch)->builtin_uint32, +++ &opts, 'g', file); +++ fprintf_filtered (file, "%s","} "); +++ +++ fprintf_filtered (file, "{f = %s, ", +++ target_float_to_string (raw_buffer, +++ builtin_type (gdbarch)->builtin_float, "%-17.9g").c_str()); +++ +++ fprintf_filtered (file, "d = %s}\n", +++ target_float_to_string (raw_buffer, +++ builtin_type (gdbarch)->builtin_double, "%-24.17g").c_str()); +++} +++ +++ +++static void +++loongarch_print_registers_info (struct gdbarch *gdbarch, struct ui_file *file, +++ struct frame_info *frame, int regnum, int all) +++{ +++ int i; +++ auto regs = &gdbarch_tdep (gdbarch)->regs; +++ const int numregs = gdbarch_num_regs (gdbarch) +++ + gdbarch_num_pseudo_regs (gdbarch); +++ +++ for (i = 0; i < numregs; i++) +++ { +++ if (regnum == -1) +++ { +++ if (regs->r == i) +++ loongarch_print_all_r_registers (gdbarch, file, frame), i += 32; +++ +++ if (all) +++ { +++ if (!gdbarch_register_reggroup_p (gdbarch, i, all_reggroup)) +++ continue; +++ } +++ else +++ { +++ if (!gdbarch_register_reggroup_p (gdbarch, i, general_reggroup)) +++ continue; +++ } +++ } +++ else if (i != regnum) +++ continue; +++ +++ if (gdbarch_register_name (gdbarch, i) == NULL +++ || *(gdbarch_register_name (gdbarch, i)) == '\0') +++ continue; +++ +++ if (gdbarch_register_reggroup_p (gdbarch, i, float_reggroup)) +++ loongarch_print_fp_register (file, frame, i); +++ else +++ default_print_registers_info (gdbarch, file, frame, i, 0); +++ } +++} +++ +++constexpr gdb_byte loongarch_default_breakpoint[] = {0x05, 0x00, 0x2a, 0x00}; +++typedef BP_MANIPULATION (loongarch_default_breakpoint) loongarch_breakpoint; +++ +++/* 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. */ +++ +++ +++/* This predicate tests whether we need to read lsx/lasx registers +++ (instead of fp registers with the same DWARF2 code +++ (thus the same internal code, though lasx/lsx/fp reg internal codes are different)) +++ according to the byte-size of requested type. */ +++ +++static int +++loongarch_fp_regnum_refers_to_lsx_lasx_p (struct gdbarch *gdbarch, int regnum, struct type *type) +++{ +++ /* Conditions: +++ 1) regnum is in "disputed" zone (fp/lsx/lasx, translated from dwarf regnum) +++ 2) type is larger than 8 bytes +++ +++ (if specified type is larger than 8 bytes, +++ then regnum refers to lsx / lasx register instead of fp register) +++ */ +++ return +++ regnum >= gdbarch_tdep(gdbarch)->regs.f +++ && regnum < gdbarch_tdep(gdbarch)->regs.f + 32 +++ && TYPE_LENGTH (type) > 8; +++} +++ +++ +++static int +++loongarch_convert_register_p (struct gdbarch *gdbarch, +++ int regnum, struct type *type) +++{ +++ return loongarch_fp_regnum_refers_to_lsx_lasx_p (gdbarch, regnum, type); +++} +++ +++static int +++loongarch_register_to_value (struct frame_info *frame, int regnum, +++ struct type *type, gdb_byte *to, +++ int *optimizedp, int *unavailablep) +++{ +++ struct gdbarch *gdbarch = get_frame_arch (frame); +++ +++ if (loongarch_fp_regnum_refers_to_lsx_lasx_p (gdbarch, regnum, type)) +++ { +++ /* Add a displacement to regnum */ +++ switch (TYPE_LENGTH (type)) +++ { +++ case 16: /* 16-byte types, access vr */ +++ if (!get_frame_register_bytes (frame, regnum + gdbarch_tdep(gdbarch)->regs.vr - gdbarch_tdep(gdbarch)->regs.f, +++ 0, 16, to, optimizedp, unavailablep)) +++ return 0; +++ break; +++ +++ +++ case 32: /* 32-byte types, access xr */ +++ if (!get_frame_register_bytes (frame, regnum + gdbarch_tdep(gdbarch)->regs.xr - gdbarch_tdep(gdbarch)->regs.f, +++ 0, 32, to, optimizedp, unavailablep)) +++ return 0; +++ break; +++ +++ default: +++ goto fail; +++ } +++ +++ *optimizedp = *unavailablep = 0; +++ return 1; // 1 for success, 0 for fail +++ } +++ +++ fail: +++ internal_error (__FILE__, __LINE__, +++ _("loongarch_register_to_value: unrecognized case")); +++} +++ +++static void +++loongarch_value_to_register (struct frame_info *frame, int regnum, +++ struct type *type, const gdb_byte *from) +++{ +++ struct gdbarch *gdbarch = get_frame_arch (frame); +++ if (loongarch_fp_regnum_refers_to_lsx_lasx_p (gdbarch, regnum, type)) +++ { +++ switch (TYPE_LENGTH (type)) +++ { +++ case 16: /* 16-byte types, access vr */ +++ put_frame_register (frame, +++ regnum + gdbarch_tdep(gdbarch)->regs.vr - gdbarch_tdep(gdbarch)->regs.f, from); +++ return; +++ +++ case 32: /* 32-byte types, access xr */ +++ put_frame_register (frame, +++ regnum + gdbarch_tdep(gdbarch)->regs.xr - gdbarch_tdep(gdbarch)->regs.f, from); +++ return; +++ } +++ } +++ +++ internal_error (__FILE__, __LINE__, +++ _("loongarch_value_to_register: unrecognized case")); +++} +++ +++ +++/* Figure out where the longjmp will land. +++ We expect the first arg to be a pointer to the jmp_buf structure +++ from which we extract the pc (LOONGARCH_JB_PC) that we will land +++ at. The pc is copied into PC. This routine returns 1 on +++ success. */ +++ +++static int +++loongarch_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc) +++{ +++ CORE_ADDR jb_addr; +++ struct gdbarch *gdbarch = get_frame_arch (frame); +++ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); +++ gdb_byte buf[tdep->jb_elt_size]; +++ +++ jb_addr = get_frame_register_unsigned (frame, LOONGARCH_A0_REGNUM); +++ +++ if (target_read_memory (jb_addr + tdep->jb_pc * tdep->jb_elt_size, buf, +++ tdep->jb_elt_size)) +++ return 0; +++ +++ *pc = extract_unsigned_integer (buf, tdep->jb_elt_size, BFD_ENDIAN_LITTLE); +++ +++ return 1; +++} +++ +++ +++static struct gdbarch * +++loongarch_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) +++{ +++ struct gdbarch *gdbarch; +++ struct gdbarch_tdep tdep_instant, *tdep; +++ struct tdesc_arch_data *tdesc_data = NULL; +++ const struct target_desc *tdesc = info.target_desc; +++ int i; +++ size_t regnum; +++ +++ tdep = &tdep_instant; +++ memset (tdep, 0, sizeof (tdep)); +++ memset (&tdep->regs, -1, sizeof (tdep->regs)); +++ +++ if (info.abfd != NULL +++ && bfd_get_flavour (info.abfd) == bfd_target_elf_flavour) +++ { +++ unsigned char eclass = elf_elfheader (info.abfd)->e_ident[EI_CLASS]; +++ int e_flags = elf_elfheader (info.abfd)->e_flags; +++ auto e_abi = e_flags & EF_LARCH_ABI; +++ +++ switch (e_abi) +++ { +++ case EF_LARCH_ABI_XLP32: +++ case EF_LARCH_ABI_LP32: +++ case EF_LARCH_ABI_LP64: +++ tdep->ef_abi = e_abi; +++ break; +++ default: +++ tdep->ef_abi = EF_LARCH_ABI_LP64; +++ } +++ } +++ else +++ tdep->ef_abi = EF_LARCH_ABI_LP64; +++ +++ /* Check any target description for validity. */ +++ if (!tdesc_has_registers (tdesc)) +++ tdesc = loongarch_get_base_target_description +++ (tdep->ef_abi == EF_LARCH_ABI_LP32 ? 32 : 64); +++ +++ int valid_p = 1; +++ const struct tdesc_feature *feature; +++ +++ feature = tdesc_find_feature (tdesc, "org.gnu.gdb.loongarch.base"); +++ if (feature == NULL) +++ return NULL; +++ regnum = 0; +++ tdesc_data = tdesc_data_alloc (); +++ +++ tdep->regs.r = regnum; +++ for (i = 0; i < 32; i++) +++ valid_p &= tdesc_numbered_register (feature, tdesc_data, regnum++, +++ loongarch_r_normal_name[i] + 1); +++ valid_p &= tdesc_numbered_register +++ (feature, tdesc_data, tdep->regs.pc = regnum++, "pc"); +++ valid_p &= tdesc_numbered_register +++ (feature, tdesc_data, tdep->regs.badvaddr = regnum++, "badvaddr"); +++ +++ if ((feature = tdesc_find_feature (tdesc, "org.gnu.gdb.loongarch.fpu"))) +++ { +++ tdep->regs.f = regnum; +++ for (i = 0; i < 32; i++) +++ valid_p &= tdesc_numbered_register (feature, tdesc_data, regnum++, +++ loongarch_f_normal_name[i] + 1); +++ tdep->regs.fcc = regnum; +++ valid_p &= tdesc_numbered_register (feature, tdesc_data, regnum++, "fcc0"); +++ valid_p &= tdesc_numbered_register (feature, tdesc_data, regnum++, "fcc1"); +++ valid_p &= tdesc_numbered_register (feature, tdesc_data, regnum++, "fcc2"); +++ valid_p &= tdesc_numbered_register (feature, tdesc_data, regnum++, "fcc3"); +++ valid_p &= tdesc_numbered_register (feature, tdesc_data, regnum++, "fcc4"); +++ valid_p &= tdesc_numbered_register (feature, tdesc_data, regnum++, "fcc5"); +++ valid_p &= tdesc_numbered_register (feature, tdesc_data, regnum++, "fcc6"); +++ valid_p &= tdesc_numbered_register (feature, tdesc_data, regnum++, "fcc7"); +++ valid_p &= tdesc_numbered_register +++ (feature, tdesc_data, tdep->regs.fcsr = regnum++, "fcsr"); +++ } +++ +++ if ((feature = tdesc_find_feature (tdesc, "org.gnu.gdb.loongarch.lbt"))) +++ { +++ tdep->regs.scr = regnum; +++ for (i = 0; i < 4; i++) +++ valid_p &= tdesc_numbered_register (feature, tdesc_data, regnum++, +++ loongarch_cr_normal_name[i] + 1); +++ valid_p &= tdesc_numbered_register +++ (feature, tdesc_data, tdep->regs.EFLAG = regnum++, "EFLAG"); +++ valid_p &= tdesc_numbered_register +++ (feature, tdesc_data, tdep->regs.lbt_top = regnum++, "lbt_top"); +++ } +++ +++ if ((feature = tdesc_find_feature (tdesc, "org.gnu.gdb.loongarch.lsx"))) +++ { +++ tdep->regs.vr = regnum; +++ for (i = 0; i < 32; i++) +++ valid_p &= tdesc_numbered_register (feature, tdesc_data, regnum++, +++ loongarch_v_normal_name[i] + 1); +++ } +++ +++ if ((feature = tdesc_find_feature (tdesc, "org.gnu.gdb.loongarch.lasx"))) +++ { +++ tdep->regs.xr = regnum; +++ for (i = 0; i < 32; i++) +++ valid_p &= tdesc_numbered_register (feature, tdesc_data, regnum++, +++ loongarch_x_normal_name[i] + 1); +++ } +++ +++ if (!valid_p) +++ { +++ tdesc_data_cleanup (tdesc_data); +++ return NULL; +++ } +++ +++ info.byte_order_for_code = BFD_ENDIAN_LITTLE; +++ +++ /* Find a candidate among the list of pre-declared architectures. */ +++ for (arches = gdbarch_list_lookup_by_info (arches, &info); +++ arches != NULL; +++ arches = gdbarch_list_lookup_by_info (arches->next, &info)) +++ { +++ if (gdbarch_tdep (arches->gdbarch)->ef_abi != tdep->ef_abi) +++ continue; +++ +++ if (tdesc_data != NULL) +++ tdesc_data_cleanup (tdesc_data); +++ +++ return arches->gdbarch; +++ } +++ +++ /* None found, so create a new architecture from the information provided. */ +++ tdep = (struct gdbarch_tdep *) xmalloc (sizeof (tdep_instant)); +++ memcpy (tdep, &tdep_instant, sizeof (tdep_instant)); +++ gdbarch = gdbarch_alloc (&info, tdep); +++ +++ /* Target data types. */ +++ switch (tdep->ef_abi) +++ { +++ case EF_LARCH_ABI_XLP32: +++ set_gdbarch_short_bit (gdbarch, 16); +++ set_gdbarch_int_bit (gdbarch, 32); +++ set_gdbarch_long_bit (gdbarch, 64); +++ set_gdbarch_long_long_bit (gdbarch, 64); +++ set_gdbarch_float_bit (gdbarch, 32); +++ set_gdbarch_double_bit (gdbarch, 64); +++ set_gdbarch_long_double_bit (gdbarch, 128); +++ set_gdbarch_long_double_format (gdbarch, floatformats_ia64_quad); +++ set_gdbarch_ptr_bit (gdbarch, 32); +++ set_gdbarch_char_signed (gdbarch, 0); +++ break; +++ case EF_LARCH_ABI_LP32: +++ set_gdbarch_short_bit (gdbarch, 16); +++ set_gdbarch_int_bit (gdbarch, 32); +++ set_gdbarch_long_bit (gdbarch, 32); +++ set_gdbarch_long_long_bit (gdbarch, 32); +++ set_gdbarch_float_bit (gdbarch, 32); +++ set_gdbarch_double_bit (gdbarch, 64); +++ set_gdbarch_long_double_bit (gdbarch, 128); +++ set_gdbarch_long_double_format (gdbarch, floatformats_ia64_quad); +++ set_gdbarch_ptr_bit (gdbarch, 32); +++ set_gdbarch_char_signed (gdbarch, 0); +++ break; +++ case EF_LARCH_ABI_LP64: +++ set_gdbarch_short_bit (gdbarch, 16); +++ set_gdbarch_int_bit (gdbarch, 32); +++ set_gdbarch_long_bit (gdbarch, 64); +++ set_gdbarch_long_long_bit (gdbarch, 64); +++ set_gdbarch_float_bit (gdbarch, 32); +++ set_gdbarch_double_bit (gdbarch, 64); +++ set_gdbarch_long_double_bit (gdbarch, 128); +++ set_gdbarch_long_double_format (gdbarch, floatformats_ia64_quad); +++ set_gdbarch_ptr_bit (gdbarch, 64); +++ set_gdbarch_char_signed (gdbarch, 0); +++ +++ tdep->regs.ra = tdep->regs.r + 1; +++ tdep->regs.sp = tdep->regs.r + 3; +++ tdep->jb_pc = LOONGARCH_JB_PC; +++ tdep->jb_elt_size = gdbarch_ptr_bit (gdbarch) / TARGET_CHAR_BIT; +++ +++ for (i = 0; i < ARRAY_SIZE (loongarch_r_normal_name); ++i) +++ if (loongarch_r_normal_name[i][0] != '\0') +++ user_reg_add (gdbarch, loongarch_r_normal_name[i] + 1, +++ value_of_loongarch_user_reg, (void *) (size_t) (tdep->regs.r + i)); +++ +++ for (i = 0; i < ARRAY_SIZE (loongarch_r_lp64_name); ++i) +++ if (loongarch_r_lp64_name[i][0] != '\0') +++ user_reg_add (gdbarch, loongarch_r_lp64_name[i] + 1, +++ value_of_loongarch_user_reg, (void *) (size_t) (tdep->regs.r + i)); +++ +++ for (i = 0; i < ARRAY_SIZE (loongarch_r_lp64_name1); ++i) +++ if (loongarch_r_lp64_name[i][0] != '\0') +++ user_reg_add (gdbarch, loongarch_r_lp64_name1[i] + 1, +++ value_of_loongarch_user_reg, (void *) (size_t) (tdep->regs.r + i)); +++ +++ /* Add float register names. */ +++ for (i = 0; i < ARRAY_SIZE (loongarch_f_normal_name); ++i) +++ { +++ if (loongarch_f_normal_name[i][0] != '\0') +++ user_reg_add (gdbarch, loongarch_f_normal_name[i] + 1, +++ value_of_loongarch_user_reg, +++ (void *) (size_t) (tdep->regs.f + i)); +++ } +++ +++ for (i = 0; i < ARRAY_SIZE (loongarch_f_lp64_name); ++i) +++ { +++ if (loongarch_f_lp64_name[i][0] != '\0') +++ user_reg_add (gdbarch, loongarch_f_lp64_name[i] + 1, +++ value_of_loongarch_user_reg, +++ (void *) (size_t) (tdep->regs.f + i)); +++ } +++ +++ for (i = 0; i < ARRAY_SIZE (loongarch_f_lp64_name1); ++i) +++ { +++ if (loongarch_f_lp64_name1[i][0] != '\0') +++ user_reg_add (gdbarch, loongarch_f_lp64_name1[i] + 1, +++ value_of_loongarch_user_reg, +++ (void *) (size_t) (tdep->regs.f + i)); +++ } +++ +++ /* Functions handling dummy frames. */ +++ set_gdbarch_push_dummy_call +++ (gdbarch, loongarch_xlp32lp64_push_dummy_call); +++ set_gdbarch_return_value (gdbarch, loongarch_xlp32lp64_return_value); +++ +++ break; +++ default: +++ gdb_assert_not_reached ("unknown ABI"); +++ } +++ +++ /* Register architecture. */ +++ set_gdbarch_num_regs (gdbarch, regnum); +++ set_gdbarch_sp_regnum (gdbarch, tdep->regs.sp); +++ set_gdbarch_pc_regnum (gdbarch, tdep->regs.pc); +++// set_gdbarch_ps_regnum (gdbarch, loongarch_FP_REGNUM); +++// set_gdbarch_deprecated_fp_regnum (gdbarch, loongarch_FP_REGNUM); +++ +++ tdesc_use_registers (gdbarch, tdesc, tdesc_data); +++ +++ /* Functions to supply register information. */ +++ set_gdbarch_register_name (gdbarch, loongarch_register_name); +++ +++ /* Handle overlapping dwarf2 register code for fp/lsx/lasx */ +++ set_gdbarch_convert_register_p (gdbarch, loongarch_convert_register_p); +++ set_gdbarch_register_to_value (gdbarch, loongarch_register_to_value); +++ set_gdbarch_value_to_register (gdbarch, loongarch_value_to_register); +++ +++ /* Functions to analyze frames. */ +++ set_gdbarch_skip_prologue (gdbarch, loongarch_skip_prologue); +++ set_gdbarch_inner_than (gdbarch, core_addr_lessthan); +++ set_gdbarch_frame_align (gdbarch, loongarch_frame_align); +++ +++ /* Functions to access frame data. */ +++ set_gdbarch_unwind_pc (gdbarch, loongarch_unwind_pc); +++ set_gdbarch_unwind_sp (gdbarch, loongarch_unwind_sp); +++ +++ set_gdbarch_dummy_id (gdbarch, loongarch_dummy_id); +++ +++ set_gdbarch_software_single_step (gdbarch, loongarch_software_single_step); +++ +++ set_gdbarch_breakpoint_kind_from_pc (gdbarch, loongarch_breakpoint::kind_from_pc); +++ set_gdbarch_sw_breakpoint_from_kind (gdbarch, loongarch_breakpoint::bp_from_kind); +++ +++ set_gdbarch_have_nonsteppable_watchpoint (gdbarch, 1); +++ +++ /* Virtual tables. */ +++ set_gdbarch_vbit_in_delta (gdbarch, 1); +++ +++ set_gdbarch_gcc_target_options (gdbarch, loongarch_gcc_target_options); +++ +++ /* Hook in OS ABI-specific overrides, if they have been registered. */ +++ info.target_desc = tdesc; +++ info.tdesc_data = tdesc_data; +++ gdbarch_init_osabi (info, gdbarch); +++ set_gdbarch_register_reggroup_p (gdbarch, loongarch_register_reggroup_p); +++ set_gdbarch_register_name (gdbarch, loongarch_register_name); +++ set_gdbarch_print_registers_info (gdbarch, loongarch_print_registers_info); +++ +++ set_gdbarch_get_longjmp_target (gdbarch, loongarch_get_longjmp_target); +++ +++ /* Frame unwinders. Use DWARF debug info if available, otherwise use our own +++ unwinder. */ +++ set_gdbarch_dwarf2_reg_to_regnum (gdbarch, loongarch_dwarf2_reg_to_regnum); +++ dwarf2_append_unwinders (gdbarch); +++ frame_unwind_append_unwinder (gdbarch, &loongarch_frame_unwind); +++ +++ return gdbarch; +++} +++ +++ +++/* Allocate new loongarch_inferior_data object. */ +++ +++// static struct loongarch_inferior_data * +++// loongarch_new_inferior_data (void) +++// { +++// struct loongarch_inferior_data *inf_data +++// = new (struct loongarch_inferior_data); +++// inf_data->misa_read = false; +++// return inf_data; +++// } +++ +++/* Free inferior data. */ +++ +++// static void +++// loongarch_inferior_data_cleanup (struct inferior *inf, void *data) +++// { +++// struct loongarch_inferior_data *inf_data = +++// static_cast (data); +++// delete (inf_data); +++// } +++ +++/* Return loongarch_inferior_data for the given INFERIOR. If not yet created, +++ construct it. */ +++ +++// struct loongarch_inferior_data * +++// loongarch_inferior_data (struct inferior *const inf) +++// { +++// struct loongarch_inferior_data *inf_data; +++ +++// gdb_assert (inf != NULL); +++ +++// inf_data +++// = (struct loongarch_inferior_data *) inferior_data (inf, loongarch_inferior_data_reg); +++// if (inf_data == NULL) +++// { +++// inf_data = loongarch_new_inferior_data (); +++// set_inferior_data (inf, loongarch_inferior_data_reg, inf_data); +++// } +++ +++// return inf_data; +++// } +++ +++/* Free the inferior data when an inferior exits. */ +++ +++// static void +++// loongarch_invalidate_inferior_data (struct inferior *inf) +++// { +++// struct loongarch_inferior_data *inf_data; +++ +++// gdb_assert (inf != NULL); +++ +++// /* Don't call loongarch_INFERIOR_DATA as we don't want to create the data if +++// we've not already created it by this point. */ +++// inf_data +++// = (struct loongarch_inferior_data *) inferior_data (inf, loongarch_inferior_data_reg); +++// if (inf_data != NULL) +++// { +++// delete (inf_data); +++// set_inferior_data (inf, loongarch_inferior_data_reg, NULL); +++// } +++// } +++ +++static void +++info_loongarch (const char *addr_exp, int from_tty) +++{ +++ char *buf, *t; +++ int set; +++ char *item; +++ unsigned long addr; +++ unsigned long long value; +++ +++ if (addr_exp) +++ { +++ addr_exp = skip_spaces (addr_exp); +++ buf = (char *) alloca (strlen (addr_exp) + 1); +++ strcpy (buf, addr_exp); +++ loongarch_eliminate_adjacent_repeat_char (buf, ' '); +++ } +++ else +++ goto Empty; +++ +++ if (!(t = strtok (buf, " "))) +++ goto Empty; +++ if (strcmp (t, "set") == 0) +++ { +++ t = strtok (NULL, " "); +++ set = 1; +++ } +++ else +++ { +++ if (strcmp (t, "get") == 0) +++ t = strtok (NULL, " "); +++ set = 0; +++ } +++ if (!(item = t)) +++ goto Empty; +++ if (!(t = strtok (NULL, " "))) +++ goto Empty; +++ addr = strtoul (t, NULL, 0); +++ if (set && (t = strtok (NULL, " ")) == NULL) +++ goto Empty; +++ value = strtoll (t, NULL, 0); +++ +++ if (set) +++ if (strcmp (item, "cpucfg") == 0) +++ { +++ uint32_t t = value; +++ ULONGEST xfered_len; +++ target_xfer_partial (current_top_target (), TARGET_OBJECT_LARCH, +++ "cpucfg", NULL, (const gdb_byte *) &t, addr * 4, sizeof (t), +++ &xfered_len); +++ if (0 < xfered_len) +++ fprintf_unfiltered (gdb_stdout, "ok\n"); +++ else +++ error ("Set failed"); +++ } +++ else +++ { +++ uint64_t t = value; +++ ULONGEST xfered_len; +++ target_xfer_partial (current_top_target (), TARGET_OBJECT_LARCH, +++ item, NULL, (const gdb_byte *) &t, addr * 8, sizeof (t), +++ &xfered_len); +++ if (0 < xfered_len) +++ fprintf_unfiltered (gdb_stdout, "ok\n"); +++ else +++ error ("Set failed"); +++ } +++ else +++ if (strcmp (item, "cpucfg") == 0) +++ { +++ uint32_t t; +++ ULONGEST xfered_len; +++ target_xfer_partial (current_top_target (), TARGET_OBJECT_LARCH, +++ "cpucfg", (gdb_byte *) &t, NULL, addr * 4, sizeof (t), +++ &xfered_len); +++ if (0 < xfered_len) +++ fprintf_unfiltered (gdb_stdout, "return is %x\n", t); +++ else +++ error ("Get failed"); +++ } +++ else +++ { +++ uint64_t t; +++ ULONGEST xfered_len; +++ target_xfer_partial (current_top_target (), TARGET_OBJECT_LARCH, +++ item, (gdb_byte *) &t, NULL, addr * 8, sizeof (t), +++ &xfered_len); +++ if (0 < xfered_len) +++ fprintf_unfiltered (gdb_stdout, "return is %llx\n", (long long) t); +++ else +++ error ("Get failed"); +++ } +++ +++ return; +++Empty: +++ error ("Empty. Should be 'info loongarch ([get]|set) item addr [value]'"); +++} +++ +++ +++#define REG_ALLOC(REGS, LENGTH, RECORD_BUF) \ +++ do \ +++ { \ +++ unsigned int reg_len = LENGTH; \ +++ if (reg_len) \ +++ { \ +++ REGS = XNEWVEC (uint32_t, reg_len); \ +++ memcpy(®S[0], &RECORD_BUF[0], sizeof(uint32_t)*LENGTH); \ +++ } \ +++ } \ +++ while (0) +++ +++#define MEM_ALLOC(MEMS, LENGTH, RECORD_BUF) \ +++ do \ +++ { \ +++ unsigned int mem_len = LENGTH; \ +++ if (mem_len) \ +++ { \ +++ MEMS = XNEWVEC (struct loongarch_mem_r, mem_len); \ +++ memcpy(&MEMS->len, &RECORD_BUF[0], \ +++ sizeof(struct loongarch_mem_r) * LENGTH); \ +++ } \ +++ } \ +++ while (0) +++ +++struct loongarch_mem_r +++{ +++ uint64_t len; /* Record length. */ +++ uint64_t addr; /* Memory address. */ +++}; +++ +++enum loongarch_record_result +++{ +++ LOONGARCH_RECORD_SUCCESS, +++ LOONGARCH_RECORD_UNSUPPORTED, +++ LOONGARCH_RECORD_UNKNOWN +++}; +++ +++typedef struct insn_decode_record_t +++{ +++ struct gdbarch *gdbarch; +++ struct regcache *regcache; +++ CORE_ADDR this_addr; /* Address of insn to be recorded. */ +++ uint32_t loongarch_insn; /* Insn to be recorded. */ +++ uint32_t mem_rec_count; /* Count of memory records. */ +++ uint32_t reg_rec_count; /* Count of register records. */ +++ uint32_t *loongarch_regs; /* Registers to be recorded. */ +++ struct loongarch_mem_r *loongarch_mems; /* Memory locations to be recorded. */ +++} insn_decode_record; +++ +++static unsigned int loongarch_record_data_process_insn_record(insn_decode_record *loongarch_insn_r){ +++ int rd; +++ uint32_t record_buf[1]; +++ auto regs = &gdbarch_tdep (loongarch_insn_r->gdbarch)->regs; +++ rd = loongarch_decode_imm ("0:5", loongarch_insn_r->loongarch_insn, 0) + regs->r; +++ record_buf[0] = rd; +++ loongarch_insn_r -> reg_rec_count = 1; +++ +++ REG_ALLOC (loongarch_insn_r->loongarch_regs, loongarch_insn_r->reg_rec_count,record_buf); +++ +++ return LOONGARCH_RECORD_SUCCESS; +++} +++ +++static unsigned int loongarch_record_read_time_insn_record(insn_decode_record *loongarch_insn_r){ +++ int rd,rj; +++ uint32_t record_buf[2]; +++ auto regs = &gdbarch_tdep (loongarch_insn_r->gdbarch)->regs; +++ rd = loongarch_decode_imm ("0:5", loongarch_insn_r->loongarch_insn, 0) + regs->r; +++ rj = loongarch_decode_imm ("5:5", loongarch_insn_r->loongarch_insn, 0) + regs->r; +++ record_buf[0] = rd; +++ record_buf[1] = rj; +++ loongarch_insn_r -> reg_rec_count = 2; +++ +++ REG_ALLOC (loongarch_insn_r->loongarch_regs, loongarch_insn_r->reg_rec_count,record_buf); +++ return LOONGARCH_RECORD_SUCCESS; +++} +++ +++static unsigned int loongarch_record_jump_insn_record(insn_decode_record *loongarch_insn_r){ +++ if(is_jirl_ins(loongarch_insn_r->loongarch_insn)){ +++ int rd; +++ uint32_t record_buf[1]; +++ auto regs = &gdbarch_tdep (loongarch_insn_r->gdbarch)->regs; +++ rd = loongarch_decode_imm ("0:5", loongarch_insn_r->loongarch_insn, 0) + regs->r; +++ record_buf[0] = rd; +++ loongarch_insn_r -> reg_rec_count = 1; +++ +++ REG_ALLOC (loongarch_insn_r->loongarch_regs, loongarch_insn_r->reg_rec_count,record_buf); +++ return LOONGARCH_RECORD_SUCCESS; +++ } +++ else if(is_bl_ins(loongarch_insn_r->loongarch_insn)){ +++ uint32_t record_buf[1]; +++ auto regs = &gdbarch_tdep (loongarch_insn_r->gdbarch)->regs; +++ record_buf[0] = regs->r + 1; +++ loongarch_insn_r -> reg_rec_count = 1; +++ +++ REG_ALLOC (loongarch_insn_r->loongarch_regs, loongarch_insn_r->reg_rec_count,record_buf); +++ return LOONGARCH_RECORD_SUCCESS; +++ } +++ return LOONGARCH_RECORD_SUCCESS; +++} +++ +++ +++//FADD.S FADD.D FSUB.S .... MOVGR2FR.D MOVGR2FRH.W +++//MOVCF2FR(only 1 bit) //FIXME:? +++//FCVT.S.D FCVT.D.S .... FRINT.S FRINT.D +++static unsigned int loongarch_record_float_data_process_insn_record(insn_decode_record *loongarch_insn_r){ +++ int fd; +++ uint32_t record_buf[1]; +++ auto regs = &gdbarch_tdep (loongarch_insn_r->gdbarch)->regs; +++ fd = loongarch_decode_imm ("0:5", loongarch_insn_r->loongarch_insn, 0) + regs->f; +++ record_buf[0] = fd; +++ loongarch_insn_r -> reg_rec_count = 1; +++ +++ REG_ALLOC (loongarch_insn_r->loongarch_regs, loongarch_insn_r->reg_rec_count,record_buf); +++ return LOONGARCH_RECORD_SUCCESS; +++} +++ +++static unsigned int loongarch_record_fcsr_process_insn_record(insn_decode_record *loongarch_insn_r){ +++ int fcsr; +++ uint32_t record_buf[1]; +++ auto regs = &gdbarch_tdep (loongarch_insn_r->gdbarch)->regs; +++ fcsr = loongarch_decode_imm ("0:5", loongarch_insn_r->loongarch_insn, 0) + regs->fcsr; +++ record_buf[0] = fcsr; +++ loongarch_insn_r -> reg_rec_count = 1; +++ +++ REG_ALLOC (loongarch_insn_r->loongarch_regs, loongarch_insn_r->reg_rec_count,record_buf); +++ return LOONGARCH_RECORD_SUCCESS; +++} +++ +++//FIXME:no cf regs +++static unsigned int loongarch_record_cf_process_insn_record(insn_decode_record *loongarch_insn_r){ +++ int cf,imm3_4; +++ uint32_t record_buf[1]; +++ cf = loongarch_decode_imm ("0:3", loongarch_insn_r->loongarch_insn, 0); +++ imm3_4 = loongarch_decode_imm ("3:2", loongarch_insn_r->loongarch_insn, 0); +++ if(imm3_4 != 0){ +++ return LOONGARCH_RECORD_UNSUPPORTED; +++ } +++ record_buf[0] = cf; +++ loongarch_insn_r -> reg_rec_count = 1; +++ +++ REG_ALLOC (loongarch_insn_r->loongarch_regs, loongarch_insn_r->reg_rec_count,record_buf); +++ return LOONGARCH_RECORD_SUCCESS; +++} +++ +++static unsigned int loongarch_record_float_insn_record(insn_decode_record *loongarch_insn_r){ +++ if(is_movgr2fcsr_ins(loongarch_insn_r->loongarch_insn)){ +++ return loongarch_record_fcsr_process_insn_record(loongarch_insn_r); +++ } else if(is_cf_ins(loongarch_insn_r->loongarch_insn)){ +++ return loongarch_record_cf_process_insn_record(loongarch_insn_r); +++ } else { +++ return loongarch_record_float_data_process_insn_record(loongarch_insn_r); +++ } +++ +++} +++ +++static unsigned int loongarch_record_store_insn_record(insn_decode_record *loongarch_insn_r){ +++ enum store_types +++ { +++ STB,STH,STW,STD,STXB,STXH,STXW,STXD,STPTRW,STPTRD,SCW,SCD,FSTS,FSTD,FSTXS,FSTXD,NOT_STORE +++ }; +++ int store_type; +++ uint64_t record_buf_mem[2]; +++ store_type = is_stb_ins(loongarch_insn_r->loongarch_insn) ? STB : +++ is_sth_ins(loongarch_insn_r->loongarch_insn) ? STH : +++ is_stw_ins(loongarch_insn_r->loongarch_insn) ? STW : +++ is_std_ins(loongarch_insn_r->loongarch_insn) ? STD : +++ is_stxb_ins(loongarch_insn_r->loongarch_insn) ? STXB : +++ is_stxh_ins(loongarch_insn_r->loongarch_insn) ? STXH : +++ is_stxw_ins(loongarch_insn_r->loongarch_insn) ? STXW : +++ is_stxd_ins(loongarch_insn_r->loongarch_insn) ? STXD : +++ is_stptrw_ins(loongarch_insn_r->loongarch_insn) ? STPTRW : +++ is_stptrd_ins(loongarch_insn_r->loongarch_insn) ? STPTRD : +++ is_scw_ins(loongarch_insn_r->loongarch_insn) ? SCW : +++ is_scd_ins(loongarch_insn_r->loongarch_insn) ? SCD : +++ is_fsts_ins(loongarch_insn_r->loongarch_insn) ? FSTS : +++ is_fstd_ins(loongarch_insn_r->loongarch_insn) ? FSTD : +++ is_fstxs_ins(loongarch_insn_r->loongarch_insn) ? FSTXS : +++ is_fstxd_ins(loongarch_insn_r->loongarch_insn) ? FSTXD : +++ NOT_STORE; +++ +++ if(store_type == STB || store_type == STH || store_type == STW || store_type == STD || store_type == FSTS || store_type == FSTD ){ +++ int rj_no; +++ int data_size; +++ int imm; +++ uint64_t rj_val; +++ uint64_t address; +++ auto regs = &gdbarch_tdep (loongarch_insn_r->gdbarch)->regs; +++ rj_no = loongarch_decode_imm ("5:5", loongarch_insn_r->loongarch_insn, 0) + regs->r ; +++ imm = loongarch_decode_imm ("10:12", loongarch_insn_r->loongarch_insn, 0); +++ regcache_raw_read_unsigned (loongarch_insn_r->regcache, rj_no, &rj_val); +++ address = rj_val + imm; +++ data_size = store_type == STB ? 1 : +++ store_type == STH ? 2 : +++ store_type == STW || store_type == FSTS ? 4 : +++ store_type == STD || store_type == FSTD ? 8 : 0; +++ record_buf_mem[0] = data_size; +++ record_buf_mem[1] = address; +++ loongarch_insn_r->mem_rec_count = 1; +++ MEM_ALLOC (loongarch_insn_r->loongarch_mems, loongarch_insn_r->mem_rec_count,record_buf_mem); +++ return LOONGARCH_RECORD_SUCCESS; +++ } +++ else if(store_type == STXB || store_type == STXH || store_type == STXW || store_type == STXD || store_type == FSTXS || store_type == FSTXD ){ +++ int data_size; +++ int rj_no,rk_no; +++ uint64_t rj_val,rk_val; +++ uint64_t address; +++ auto regs = &gdbarch_tdep (loongarch_insn_r->gdbarch)->regs; +++ rj_no = loongarch_decode_imm ("5:5", loongarch_insn_r->loongarch_insn, 0) + regs->r ; +++ rk_no = loongarch_decode_imm ("10:5", loongarch_insn_r->loongarch_insn, 0) + regs->r ; +++ regcache_raw_read_unsigned (loongarch_insn_r->regcache, rj_no, &rj_val); +++ regcache_raw_read_unsigned (loongarch_insn_r->regcache, rk_no, &rk_val); +++ address = rj_val + rk_val; +++ data_size = store_type == STXB ? 1 : +++ store_type == STXH ? 2 : +++ store_type == STXW || store_type == FSTXS ? 4 : +++ store_type == STXD || store_type == FSTXD ? 8 : 0; +++ record_buf_mem[0] = data_size; +++ record_buf_mem[1] = address; +++ loongarch_insn_r->mem_rec_count = 1; +++ MEM_ALLOC (loongarch_insn_r->loongarch_mems, loongarch_insn_r->mem_rec_count,record_buf_mem); +++ return LOONGARCH_RECORD_SUCCESS; +++ }else if(store_type == STPTRW || store_type == STPTRD || store_type == SCW || store_type == SCD){ //FIXME:sc.w and sc.d correct the LLbit? Is LLit a register? +++ int data_size; +++ int rj_no; +++ int imm; +++ uint64_t rj_val; +++ uint64_t address; +++ auto regs = &gdbarch_tdep (loongarch_insn_r->gdbarch)->regs; +++ rj_no = loongarch_decode_imm ("5:5", loongarch_insn_r->loongarch_insn, 0) + regs->r ; +++ imm = loongarch_decode_imm ("10:14", loongarch_insn_r->loongarch_insn, 0); +++ regcache_raw_read_unsigned (loongarch_insn_r->regcache, rj_no, &rj_val); +++ address = rj_val + imm; +++ data_size = store_type == STPTRW || store_type == SCW ? 4 : +++ store_type == STPTRD || store_type == SCD ? 8 : 0; +++ record_buf_mem[0] = data_size; +++ record_buf_mem[1] = address; +++ loongarch_insn_r->mem_rec_count = 1; +++ MEM_ALLOC (loongarch_insn_r->loongarch_mems, loongarch_insn_r->mem_rec_count,record_buf_mem); +++ return LOONGARCH_RECORD_SUCCESS; +++ } +++ return LOONGARCH_RECORD_UNSUPPORTED; +++} +++ +++static unsigned int loongarch_record_am_insn_record(insn_decode_record *loongarch_insn_r){ +++ int rj_no,rd_no; +++ int word_or_double; +++ int data_size; +++ uint64_t address; +++ +++ uint32_t record_buf[1]; +++ uint64_t record_buf_mem[2]; +++ auto regs = &gdbarch_tdep (loongarch_insn_r->gdbarch)->regs; +++ rd_no = loongarch_decode_imm ("0:5", loongarch_insn_r->loongarch_insn, 0) + regs->r; +++ rj_no = loongarch_decode_imm ("5:5", loongarch_insn_r->loongarch_insn, 0) + regs->r; +++ word_or_double = loongarch_decode_imm ("15:1", loongarch_insn_r->loongarch_insn, 0); +++ regcache_raw_read_unsigned (loongarch_insn_r->regcache, rj_no, &address); +++ data_size = word_or_double == 1 ? 8 : 4; +++ record_buf[0] = rd_no; +++ loongarch_insn_r -> reg_rec_count = 1; +++ +++ record_buf_mem[0] = data_size; +++ record_buf_mem[1] = address; +++ loongarch_insn_r->mem_rec_count = 1; +++ +++ REG_ALLOC (loongarch_insn_r->loongarch_regs, loongarch_insn_r->reg_rec_count,record_buf); +++ MEM_ALLOC (loongarch_insn_r->loongarch_mems, loongarch_insn_r->mem_rec_count,record_buf_mem); +++ +++ return LOONGARCH_RECORD_SUCCESS; +++} +++ +++static unsigned int loongarch_record_cond_load_insn_record(insn_decode_record *loongarch_insn_r){ +++ int rd_no,rj_no,rk_no,fd_no; +++ uint64_t rj_val,rk_val; +++ auto regs = &gdbarch_tdep (loongarch_insn_r->gdbarch)->regs; +++ rd_no = loongarch_decode_imm ("0:5", loongarch_insn_r->loongarch_insn, 0) + regs->r; +++ fd_no = loongarch_decode_imm ("0:5", loongarch_insn_r->loongarch_insn, 0) + regs->f; +++ rj_no = loongarch_decode_imm ("5:5", loongarch_insn_r->loongarch_insn, 0) + regs->r; +++ rk_no = loongarch_decode_imm ("10:5", loongarch_insn_r->loongarch_insn, 0) + regs->r; +++ regcache_raw_read_unsigned (loongarch_insn_r->regcache, rj_no, &rj_val); +++ regcache_raw_read_unsigned (loongarch_insn_r->regcache, rk_no, &rk_val); +++ +++ if((is_ldgt_ins(loongarch_insn_r->loongarch_insn) && (rj_val > rk_val)) || +++ (is_ldle_ins(loongarch_insn_r->loongarch_insn) && (rj_val <= rk_val)) ){ +++ uint32_t record_buf[1]; +++ record_buf[0] = rd_no; +++ loongarch_insn_r -> reg_rec_count = 1; +++ REG_ALLOC (loongarch_insn_r->loongarch_regs, loongarch_insn_r->reg_rec_count,record_buf); +++ +++ } +++ else if((is_fldgt_ins(loongarch_insn_r->loongarch_insn) && (rj_val > rk_val)) || +++ (is_fldle_ins(loongarch_insn_r->loongarch_insn) && (rj_val <= rk_val)) ){ +++ uint32_t record_buf[1]; +++ record_buf[0] = fd_no; +++ loongarch_insn_r -> reg_rec_count = 1; +++ REG_ALLOC (loongarch_insn_r->loongarch_regs, loongarch_insn_r->reg_rec_count,record_buf); +++ } +++ return LOONGARCH_RECORD_SUCCESS; +++} +++ +++static unsigned int loongarch_record_cond_store_insn_record(insn_decode_record *loongarch_insn_r){ +++ int rj_no,rk_no; +++ int data_size; +++ uint64_t rj_val,rk_val; +++ auto regs = &gdbarch_tdep (loongarch_insn_r->gdbarch)->regs; +++ rj_no = loongarch_decode_imm ("5:5", loongarch_insn_r->loongarch_insn, 0) + regs->r; +++ rk_no = loongarch_decode_imm ("10:5", loongarch_insn_r->loongarch_insn, 0) + regs->r; +++ regcache_raw_read_unsigned (loongarch_insn_r->regcache, rj_no, &rj_val); +++ regcache_raw_read_unsigned (loongarch_insn_r->regcache, rk_no, &rk_val); +++ +++ +++ if((is_stgt_ins(loongarch_insn_r->loongarch_insn) && (rj_val > rk_val)) || +++ (is_stle_ins(loongarch_insn_r->loongarch_insn) && (rj_val <= rk_val)) ){ +++ uint64_t record_buf_mem[2]; +++ data_size = (loongarch_insn_r->loongarch_insn & 0x00018000) == 0x00000000 ? 1 : +++ (loongarch_insn_r->loongarch_insn & 0x00018000) == 0x00008000 ? 2 : +++ (loongarch_insn_r->loongarch_insn & 0x00018000) == 0x00010000 ? 4 : +++ (loongarch_insn_r->loongarch_insn & 0x00018000) == 0x00018000 ? 8 : 0; +++ record_buf_mem[0] = data_size; +++ record_buf_mem[1] = rj_val; +++ loongarch_insn_r->mem_rec_count = 1; +++ MEM_ALLOC (loongarch_insn_r->loongarch_mems, loongarch_insn_r->mem_rec_count,record_buf_mem); +++ } +++ +++ else if((is_fstgt_ins(loongarch_insn_r->loongarch_insn) && (rj_val > rk_val)) || +++ (is_fstle_ins(loongarch_insn_r->loongarch_insn) && (rj_val <= rk_val)) ){ +++ uint64_t record_buf_mem[2]; +++ data_size = (loongarch_insn_r->loongarch_insn & 0x00008000) == 0x00000000 ? 4 : +++ (loongarch_insn_r->loongarch_insn & 0x00008000) == 0x00008000 ? 8 : 0; +++ record_buf_mem[0] = data_size; +++ record_buf_mem[1] = rj_val; +++ loongarch_insn_r->mem_rec_count = 1; +++ MEM_ALLOC (loongarch_insn_r->loongarch_mems, loongarch_insn_r->mem_rec_count,record_buf_mem); +++ } +++ +++ return LOONGARCH_RECORD_SUCCESS; +++} +++ +++static unsigned int loongarch_record_nop_insn_record(insn_decode_record *loongarch_insn_r){ +++ return LOONGARCH_RECORD_SUCCESS; +++} +++ +++/* Decodes insns type and invokes its record handler. */ +++static unsigned int loongarch_record_decode_insn_handler(insn_decode_record *loongarch_insn_r){ +++ if(is_data_process_ins(loongarch_insn_r->loongarch_insn)){ +++ return loongarch_record_data_process_insn_record(loongarch_insn_r); +++ } else if(is_jump_ins(loongarch_insn_r->loongarch_insn)){ +++ return loongarch_record_jump_insn_record(loongarch_insn_r); +++ } else if(is_store_ins(loongarch_insn_r->loongarch_insn)){ +++ return loongarch_record_store_insn_record(loongarch_insn_r); +++ } else if(is_read_time_ins(loongarch_insn_r->loongarch_insn)){ +++ return loongarch_record_read_time_insn_record(loongarch_insn_r); +++ } else if(is_float_ins(loongarch_insn_r->loongarch_insn)){ +++ return loongarch_record_float_insn_record(loongarch_insn_r); +++ } else if(is_nop_ins(loongarch_insn_r->loongarch_insn)){ +++ return loongarch_record_nop_insn_record(loongarch_insn_r); +++ } else if(is_am_ins(loongarch_insn_r->loongarch_insn)){ +++ return loongarch_record_am_insn_record(loongarch_insn_r); +++ } else if(is_cond_load_ins(loongarch_insn_r->loongarch_insn)){ +++ return loongarch_record_cond_load_insn_record(loongarch_insn_r); +++ } else if(is_cond_store_ins(loongarch_insn_r->loongarch_insn)){ +++ return loongarch_record_cond_store_insn_record(loongarch_insn_r); +++ } +++ printf("DEBUG INFO:instruction handler cannot decode the instruction:%08x.\n",loongarch_insn_r->loongarch_insn); +++// printf("DEBUG INFO:the instruction %08x is nop? : %d is syscall? %d\n",loongarch_insn_r->loongarch_insn,is_nop_ins(loongarch_insn_r->loongarch_insn)); +++ return LOONGARCH_RECORD_UNSUPPORTED; +++} +++/* +++static void print_all_registers(insn_decode_record *loongarch_insn_r){ +++ uint64_t reg_val; +++ int reg_no = 0; +++ for(reg_no = 0; reg_no < 33; reg_no++){ +++ regcache_raw_read_unsigned (loongarch_insn_r->regcache, reg_no, ®_val); +++ printf("REGISTER INFO:The value of REG %d is %lu\n",reg_no,reg_val); +++ } +++ printf("SIZE INFO:size of CORE_ADDR is %lu,size of unsigned long int is %lu, size of uint32_t is %lu",sizeof(CORE_ADDR),sizeof(unsigned long int),sizeof(uint32_t)); +++ return; +++} +++*/ +++int loongarch_process_record (struct gdbarch *gdbarch, struct regcache *regcache, CORE_ADDR insn_addr) +++{ +++ +++ int no_of_rec = 0; +++ uint32_t ret = 0; +++ insn_decode_record loongarch_record; +++ auto regs = &gdbarch_tdep (gdbarch)->regs; +++ /* reset the content of loongarch_record */ +++ memset (&loongarch_record, 0, sizeof (insn_decode_record)); +++ /* write the loongarch_record */ +++ loongarch_record.gdbarch = gdbarch; +++ loongarch_record.regcache = regcache; +++ loongarch_record.this_addr = insn_addr; +++ /* Get the current instruction */ +++ loongarch_record.loongarch_insn = (uint32_t) loongarch_fetch_instruction (insn_addr, NULL); +++ ret = loongarch_record_decode_insn_handler (&loongarch_record); +++ if (ret == LOONGARCH_RECORD_UNSUPPORTED) { +++// printf_unfiltered (_("DEBUG INFO:Process record does not support instruction 0x%08x at address %s.\n"),loongarch_record.loongarch_insn, paddress (gdbarch, insn_addr)); +++ ret = -1; +++ } +++ if (ret == LOONGARCH_RECORD_SUCCESS) { +++ /* Record registers. */ +++// printf("DEBUG INFO:decode end, fill the changed registers\n"); +++ record_full_arch_list_add_reg (loongarch_record.regcache,regs->pc); +++ if (loongarch_record.loongarch_regs) { +++ for (no_of_rec = 0; no_of_rec < loongarch_record.reg_rec_count; no_of_rec++) { +++ if (record_full_arch_list_add_reg(loongarch_record.regcache , loongarch_record.loongarch_regs[no_of_rec])) +++ ret = -1; +++ } +++ } +++ +++ /* Record memories. */ +++// printf("DEBUG INFO:decode end, fill the changed memories\n"); +++ if (loongarch_record.loongarch_mems) { +++ for (no_of_rec = 0; no_of_rec < loongarch_record.mem_rec_count; no_of_rec++) { +++ if (record_full_arch_list_add_mem((CORE_ADDR)loongarch_record.loongarch_mems[no_of_rec].addr,loongarch_record.loongarch_mems[no_of_rec].len)) +++ ret = -1; +++ } +++ } +++// printf("DEBUG INFO:fill end\n"); +++ if (record_full_arch_list_add_end ()) +++ ret = -1; +++ } +++ return ret; +++} +++ +++void +++_initialize_loongarch_tdep (void) +++{ +++ gdbarch_register (bfd_arch_loongarch, loongarch_gdbarch_init, NULL); +++ +++ add_info ("loongarch", info_loongarch, _("Loongarch extra")); +++ +++ /* Debug this files internals. */ +++ add_setshow_zuinteger_cmd ("loongarch", class_maintenance, +++ &loongarch_debug, _("\ +++Set loongarch debugging."), _("\ +++Show loongarch debugging."), _("\ +++When non-zero, loongarch specific debugging is enabled."), +++ NULL, +++ NULL, +++ &setdebuglist, &showdebuglist); +++} ++diff --git gdb-10.2/gdb/loongarch-tdep.h gdb-10.2/gdb/loongarch-tdep.h ++new file mode 100644 ++index 0000000..0d6dab6 ++--- /dev/null +++++ gdb-10.2/gdb/loongarch-tdep.h ++@@ -0,0 +1,99 @@ +++/* Target-dependent header for the RISC-V architecture, for GDB, the GNU Debugger. +++ +++ Copyright (C) 2018 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 . */ +++ +++#ifndef LOONGARCH_TDEP_H +++#define LOONGARCH_TDEP_H +++ +++#include "arch/loongarch.h" +++ +++/* Register numbers of important registers. Note that most of +++ these values are "real" register numbers, and correspond to the +++ general registers of the machine. */ +++#define LOONGARCH_A0_REGNUM 4 /* Loc of first arg */ +++ +++ +++struct gdbarch_tdep +++{ +++ /* 思来想去,我不太希望考虑CPU型号、体系结构变种之间的种种差别。LARCH指令集被 +++ 强调为增量的,可执行文件的关键就是那个EM_MACHINE和ABI,动态连接器不会因为 +++ 诸如CPU型号,指令集之类的差别拒绝执行可执行程序。至于同一个函数的不同实现 +++ (比如向量的memcpy),交给IFUNC来搞。考虑到LARCH的发展,可能其中个别指令 +++ 的意义真的因为个别CPU发生改变;或者同一个指令编码的实际指令不同,这就意味 +++ 着反汇编器状态有差别,那么ELF包含体系结构信息是必要的,否则无法分析文件。 +++ 这延伸出来几个问题: +++ 1、如何将体系结构信息存入ELF文件? +++ MIPS带来的问题是指令集充分发展使得FLAG域中的名字空间不够。这里初步设想 +++ 使用段的存在来标记指令集信息。比如ELF文件中有LASX指令,那么有一个名为 +++ LARCH.ISA.LASX的空段。类似的,我们将反汇编器的状态都记录在ELF文件中, +++ 这样就可以分析一个可执行文件了。 +++ 2、当GDB拿到可执行文件时,什么对GDB来说是至关重要的? +++ 机器之间的差别是客观的,可执行文件之间内容的差别也是客观的;但可执行 +++ 文件本身的地位是平等的。但总是需要配置GDB,让GDB可以或不可以调试某些 +++ 可执行程序。如果GDB不能调试一个可执行文件,那可能是什么原因?我想来想 +++ 去,还是因为数据模型——如果我们认为long int类型的位宽不同,我们进行 +++ 源码级调试的视角就不同,除此之外都无所谓。 +++ 如果一个程序使用了向量指令而另一个程序没有,那我们认为世界上所有程序都 +++ 使用了向量指令——如果操作系统无法访问向量寄存器,GDB将自己的register +++ cache全填上1。如果一个程序是32位的而另一个程序是64位的,那我们认为世界 +++ 上所有程序都是64位的,对于真正的32位程序,GDB内部认为高32位是低32位的 +++ 符号扩展。总之,GDB内部表示总是拥有LARCH最强的能力,如果这个能力和操作 +++ 系统有差别,那么多出来的部分被填上特殊值。 +++ 在LARCH中,数据模型信息包含在ABI中,因此我们认为ABI是gdbarch_tdep的主键 +++ 3、GDB如何对外显示?以及GDB内部某些实现策略 +++ 对于双精度浮点寄存器、128b和256b的向量寄存器有重合的关系,如果我们将 +++ */ +++ int ef_abi; /* EF_LARCH_ABI */ +++ +++ /* Offset to PC value in jump buffer. If this is negative, longjmp +++ support will be disabled. */ +++ int jb_pc; +++ +++ /* And the size of each entry in the buf. */ +++ int jb_elt_size; +++ +++ struct +++ { +++ int r; +++ int ra; +++ int sp; +++ int pc; +++ int badvaddr; +++ +++ int f; +++ int fcc; +++ int fcsr; +++ int vr; +++ int xr; +++ +++ int scr; +++ int EFLAG; +++ int lbt_top; +++ +++ } regs; +++ +++ int (*loongarch_syscall_record) (struct regcache *regcache, unsigned long svc_number); +++ +++ /* Return the expected next PC if FRAME is stopped at a syscall +++ instruction. */ +++ CORE_ADDR (*syscall_next_pc) (struct frame_info *frame); +++}; +++ +++extern int loongarch_process_record(struct gdbarch *gdbarch, struct regcache *regcache, CORE_ADDR addr); +++ +++#endif /* LOONGARCH_TDEP_H */ ++diff --git gdb-10.2/gdb/nat/loongarch-linux-watch.c gdb-10.2/gdb/nat/loongarch-linux-watch.c ++new file mode 100644 ++index 0000000..f7c0dbf ++--- /dev/null +++++ gdb-10.2/gdb/nat/loongarch-linux-watch.c ++@@ -0,0 +1,330 @@ +++/* Copyright (C) 2021 Free Software Foundation, Inc. +++ Contributed by Loongson Ltd. +++ +++ This file is part of GDB. +++ +++ Based on MIPS target. +++ +++ This program is free software; you can redistribute it and/or modify +++ it under the terms of the GNU General Public License as published by +++ the Free Software Foundation; either version 3 of the License, or +++ (at your option) any later version. +++ +++ This program is distributed in the hope that it will be useful, +++ but WITHOUT ANY WARRANTY; without even the implied warranty of +++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +++ GNU General Public License for more details. +++ +++ You should have received a copy of the GNU General Public License +++ along with this program. If not, see . */ +++ +++#include "gdbsupport/common-defs.h" +++#include "nat/gdb_ptrace.h" +++#include "loongarch-linux-watch.h" +++ +++/* Assuming usable watch registers REGS, return the irwmask of +++ register N. */ +++ +++uint8_t +++loongarch_linux_watch_get_irwmask (struct pt_watch_regs *regs, int n) +++{ +++ switch (regs->style) +++ { +++ case pt_watch_style_la32: +++ return regs->la32[n].irwmask & IRW_MASK; +++ case pt_watch_style_la64: +++ return regs->la64[n].irwmask & IRW_MASK; +++ default: +++ internal_error (__FILE__, __LINE__, +++ _ ("Unrecognized watch register style")); +++ } +++} +++ +++/* Assuming usable watch registers REGS, return the irwstat of +++ register N. */ +++ +++uint8_t +++loongarch_linux_watch_get_irwstat (struct pt_watch_regs *regs, int n) +++{ +++ switch (regs->style) +++ { +++ case pt_watch_style_la32: +++ return regs->la32[n].irwstat & IRW_MASK; +++ case pt_watch_style_la64: +++ return regs->la64[n].irwstat & IRW_MASK; +++ default: +++ internal_error (__FILE__, __LINE__, +++ _ ("Unrecognized watch register style")); +++ } +++} +++ +++/* Assuming usable watch registers REGS, return the num_valid. */ +++ +++uint32_t +++loongarch_linux_watch_get_num_valid (struct pt_watch_regs *regs) +++{ +++ return regs->num_valid; +++} +++ +++/* Assuming usable watch registers REGS, return the addr of +++ register N. */ +++ +++CORE_ADDR +++loongarch_linux_watch_get_addr (struct pt_watch_regs *regs, int n) +++{ +++ switch (regs->style) +++ { +++ case pt_watch_style_la32: +++ return regs->la32[n].addr; +++ case pt_watch_style_la64: +++ return regs->la64[n].addr; +++ default: +++ internal_error (__FILE__, __LINE__, +++ _ ("Unrecognized watch register style")); +++ } +++} +++ +++/* Assuming usable watch registers REGS, set addr of register N to +++ VALUE. */ +++ +++void +++loongarch_linux_watch_set_addr (struct pt_watch_regs *regs, int n, +++ CORE_ADDR value) +++{ +++ switch (regs->style) +++ { +++ case pt_watch_style_la32: +++ /* The cast will never throw away bits as 64 bit addresses can +++ never be used on a 32 bit kernel. */ +++ regs->la32[n].addr = (uint32_t) value; +++ break; +++ case pt_watch_style_la64: +++ regs->la64[n].addr = value; +++ break; +++ default: +++ internal_error (__FILE__, __LINE__, +++ _ ("Unrecognized watch register style")); +++ } +++} +++ +++/* Assuming usable watch registers REGS, return the mask of +++ register N. */ +++ +++CORE_ADDR +++loongarch_linux_watch_get_mask (struct pt_watch_regs *regs, int n) +++{ +++ switch (regs->style) +++ { +++ case pt_watch_style_la32: +++ return regs->la32[n].mask; +++ case pt_watch_style_la64: +++ return regs->la64[n].mask; +++ default: +++ internal_error (__FILE__, __LINE__, +++ _ ("Unrecognized watch register style")); +++ } +++} +++ +++/* Assuming usable watch registers REGS, set mask of register N to +++ VALUE. */ +++ +++void +++loongarch_linux_watch_set_mask (struct pt_watch_regs *regs, int n, +++ CORE_ADDR value) +++{ +++ switch (regs->style) +++ { +++ case pt_watch_style_la32: +++ regs->la32[n].mask = value; +++ break; +++ case pt_watch_style_la64: +++ regs->la64[n].mask = value; +++ break; +++ default: +++ internal_error (__FILE__, __LINE__, +++ _ ("Unrecognized watch register style")); +++ } +++} +++ +++/* Assuming usable watch registers REGS, return the irw of +++ register N. */ +++ +++uint8_t +++loongarch_linux_watch_get_irw (struct pt_watch_regs *regs, int n) +++{ +++ switch (regs->style) +++ { +++ case pt_watch_style_la32: +++ return regs->la32[n].irw; +++ case pt_watch_style_la64: +++ return regs->la64[n].irw; +++ default: +++ internal_error (__FILE__, __LINE__, +++ _ ("Unrecognized watch register style")); +++ } +++} +++ +++/* Assuming usable watch registers REGS, set irw of register N to +++ VALUE. */ +++ +++void +++loongarch_linux_watch_set_irw (struct pt_watch_regs *regs, int n, +++ uint8_t value) +++{ +++ switch (regs->style) +++ { +++ case pt_watch_style_la32: +++ regs->la32[n].irw = value; +++ break; +++ case pt_watch_style_la64: +++ regs->la64[n].irw = value; +++ break; +++ default: +++ internal_error (__FILE__, __LINE__, +++ _ ("Unrecognized watch register style")); +++ } +++} +++ +++/* Read the watch registers of process LWPID and store it in +++ WATCH_READBACK. Save true to *WATCH_READBACK_VALID if watch +++ registers are valid. Return 1 if watch registers are usable. +++ Cached information is used unless FORCE is true. */ +++ +++int +++loongarch_linux_read_watch_registers (long lwpid, +++ struct pt_watch_regs *watch_readback, +++ int *watch_readback_valid, int force) +++{ +++ if (force || *watch_readback_valid == 0) +++ { +++ if (ptrace (PTRACE_GET_WATCH_REGS, lwpid, watch_readback, NULL) == -1) +++ { +++ *watch_readback_valid = -1; +++ return 0; +++ } +++ if (watch_readback->num_valid == 0) +++ { +++ *watch_readback_valid = -1; +++ return 0; +++ } +++ /* Watch registers appear to be usable. */ +++ *watch_readback_valid = 1; +++ } +++ return (*watch_readback_valid == 1) ? 1 : 0; +++} +++ +++/* Convert GDB's TYPE to an IRW mask. */ +++ +++uint32_t +++loongarch_linux_watch_type_to_irw (enum target_hw_bp_type type) +++{ +++ switch (type) +++ { +++ case hw_write: +++ return W_MASK; +++ case hw_read: +++ return R_MASK; +++ case hw_access: +++ return (W_MASK | R_MASK); +++ case hw_execute: +++ return I_MASK; +++ default: +++ return 0; +++ } +++} +++ +++/* Set any low order bits in MASK that are not set. */ +++ +++static CORE_ADDR +++fill_mask (CORE_ADDR mask) +++{ +++ CORE_ADDR f = 1; +++ +++ while (f && f < mask) +++ { +++ mask |= f; +++ f <<= 1; +++ } +++ return mask; +++} +++ +++/* Try to add a single watch to the specified registers REGS. The +++ address of added watch is ADDR, the length is LEN, and the mask +++ is IRW. Return 1 on success, 0 on failure. */ +++ +++int +++loongarch_linux_watch_try_one_watch (struct pt_watch_regs *regs, +++ CORE_ADDR addr, int len, uint32_t irw) +++{ +++ CORE_ADDR base_addr, last_byte; +++ CORE_ADDR mask_bits, t_addr, t_mask; +++ uint8_t t_irw; +++ int i; +++ +++ if (len <= 0) +++ return 0; +++ +++ last_byte = addr + len - 1; +++ mask_bits = fill_mask (addr ^ last_byte); +++ base_addr = addr & ~mask_bits; +++ +++ /* Check to see if it is covered by current registers. */ +++ for (i = 0; i < loongarch_linux_watch_get_num_valid (regs); i++) +++ { +++ t_addr = loongarch_linux_watch_get_addr (regs, i); +++ t_irw = loongarch_linux_watch_get_irw (regs, i); +++ if (t_addr != 0 && irw == ((uint32_t) t_irw & irw)) +++ { +++ t_mask = loongarch_linux_watch_get_mask (regs, i); +++ if (addr >= t_addr && last_byte <= (t_addr + t_mask)) +++ return 1; +++ } +++ } +++ /* Try to find an empty register. */ +++ for (i = 0; i < loongarch_linux_watch_get_num_valid (regs); i++) +++ { +++ t_addr = loongarch_linux_watch_get_addr (regs, i); +++ if (t_addr == 0 +++ && irw == (loongarch_linux_watch_get_irwmask (regs, i) & irw)) +++ { +++ /* It fits, we'll take it. */ +++ loongarch_linux_watch_set_addr (regs, i, base_addr); +++ loongarch_linux_watch_set_mask (regs, i, mask_bits); +++ loongarch_linux_watch_set_irw (regs, i, irw); +++ return 1; +++ } +++ } +++ /* It didn't fit anywhere, we failed. */ +++ return 0; +++} +++ +++/* Fill in the watch registers REGS with the currently cached +++ watches CURRENT_WATCHES. */ +++ +++void +++loongarch_linux_watch_populate_regs ( +++ struct loongarch_watchpoint *current_watches, struct pt_watch_regs *regs) +++{ +++ struct loongarch_watchpoint *w; +++ int i; +++ +++ /* Clear them out. */ +++ for (i = 0; i < loongarch_linux_watch_get_num_valid (regs); i++) +++ { +++ loongarch_linux_watch_set_addr (regs, i, 0); +++ loongarch_linux_watch_set_mask (regs, i, 0); +++ loongarch_linux_watch_set_irw (regs, i, 0); +++ } +++ +++ w = current_watches; +++ while (w) +++ { +++ uint32_t irw = loongarch_linux_watch_type_to_irw (w->type); +++ +++ i = loongarch_linux_watch_try_one_watch (regs, w->addr, w->len, irw); +++ /* They must all fit, because we previously calculated that they +++ would. */ +++ gdb_assert (i); +++ w = w->next; +++ } +++} ++diff --git gdb-10.2/gdb/nat/loongarch-linux-watch.h gdb-10.2/gdb/nat/loongarch-linux-watch.h ++new file mode 100644 ++index 0000000..ab80b44 ++--- /dev/null +++++ gdb-10.2/gdb/nat/loongarch-linux-watch.h ++@@ -0,0 +1,132 @@ +++/* Copyright (C) 2021 Free Software Foundation, Inc. +++ Contributed by Loongson Ltd. +++ +++ This file is part of GDB. +++ +++ Based on MIPS target. +++ +++ 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 . */ +++ +++#ifndef LOONGARCH_LINUX_WATCH_H +++#define LOONGARCH_LINUX_WATCH_H 1 +++ +++#include +++#include "gdbsupport/break-common.h" +++ +++#define MAX_DEBUG_REGISTER 16 +++ +++/* If macro PTRACE_GET_WATCH_REGS is not defined, kernel header doesn't +++ have hardware watchpoint-related structures. Define them below. */ +++ +++#ifndef PTRACE_GET_WATCH_REGS +++#define PTRACE_GET_WATCH_REGS 0xd0 +++#define PTRACE_SET_WATCH_REGS 0xd1 +++ +++enum pt_watch_style +++{ +++ pt_watch_style_la32, +++ pt_watch_style_la64 +++}; +++ +++/* A value of zero in a watchlo indicates that it is available. */ +++ +++struct la32_watch_regs +++{ +++ uint32_t addr; +++ /* Lower 16 bits of watchhi. */ +++ uint32_t mask; +++ /* Valid mask and I R W bits. +++ * bit 0 -- 1 if W bit is usable. +++ * bit 1 -- 1 if R bit is usable. +++ * bit 2 -- 1 if I bit is usable. +++ * bits 3 - 11 -- Valid watchhi mask bits. +++ */ +++ uint8_t irw; +++ uint8_t irwstat; +++ uint8_t irwmask; +++ /* There is confusion across gcc versions about structure alignment, +++ so we force 8 byte alignment for these structures so they match +++ the kernel even if it was build with a different gcc version. */ +++} __attribute__ ((aligned (8))); +++ +++struct la64_watch_regs +++{ +++ uint64_t addr; +++ uint64_t mask; +++ uint8_t irw; +++ uint8_t irwstat; +++ uint8_t irwmask; +++} __attribute__ ((aligned (8))); +++ +++struct pt_watch_regs +++{ +++ uint16_t max_valid; +++ uint16_t num_valid; +++ enum pt_watch_style style; +++ union +++ { +++ struct la32_watch_regs la32[MAX_DEBUG_REGISTER]; +++ struct la64_watch_regs la64[MAX_DEBUG_REGISTER]; +++ }; +++}; +++ +++#endif /* !PTRACE_GET_WATCH_REGS */ +++ +++#define W_BIT 0 +++#define R_BIT 1 +++#define I_BIT 2 +++ +++#define W_MASK (1 << W_BIT) +++#define R_MASK (1 << R_BIT) +++#define I_MASK (1 << I_BIT) +++ +++#define IRW_MASK (I_MASK | R_MASK | W_MASK) +++ +++/* We keep list of all watchpoints we should install and calculate the +++ watch register values each time the list changes. This allows for +++ easy sharing of watch registers for more than one watchpoint. */ +++ +++struct loongarch_watchpoint +++{ +++ CORE_ADDR addr; +++ int len; +++ enum target_hw_bp_type type; +++ struct loongarch_watchpoint *next; +++}; +++ +++uint32_t loongarch_linux_watch_get_num_valid (struct pt_watch_regs *regs); +++uint8_t loongarch_linux_watch_get_irwmask (struct pt_watch_regs *regs, int n); +++uint8_t loongarch_linux_watch_get_irwstat (struct pt_watch_regs *regs, int n); +++CORE_ADDR loongarch_linux_watch_get_addr (struct pt_watch_regs *regs, int n); +++void loongarch_linux_watch_set_addr (struct pt_watch_regs *regs, int n, +++ CORE_ADDR value); +++CORE_ADDR loongarch_linux_watch_get_mask (struct pt_watch_regs *regs, int n); +++void loongarch_linux_watch_set_mask (struct pt_watch_regs *regs, int n, +++ CORE_ADDR value); +++uint8_t loongarch_linux_watch_get_irw (struct pt_watch_regs *regs, int n); +++void loongarch_linux_watch_set_irw (struct pt_watch_regs *regs, int n, +++ uint8_t value); +++int loongarch_linux_watch_try_one_watch (struct pt_watch_regs *regs, +++ CORE_ADDR addr, int len, +++ uint32_t irw); +++void loongarch_linux_watch_populate_regs ( +++ struct loongarch_watchpoint *current_watches, struct pt_watch_regs *regs); +++uint32_t loongarch_linux_watch_type_to_irw (enum target_hw_bp_type type); +++ +++int loongarch_linux_read_watch_registers (long lwpid, +++ struct pt_watch_regs *watch_readback, +++ int *watch_readback_valid, +++ int force); +++ +++#endif /* #define LOONGARCH_LINUX_WATCH_H */ ++diff --git gdb-10.2/gdb/remote.c gdb-10.2/gdb/remote.c ++index 4896c2a..f306a3d 100644 ++--- gdb-10.2/gdb/remote.c +++++ gdb-10.2/gdb/remote.c ++@@ -1983,6 +1983,8 @@ enum { ++ PACKET_qXfer_statictrace_read, ++ PACKET_qXfer_traceframe_info, ++ PACKET_qXfer_uib, +++ PACKET_qXfer_loongarch_read, +++ PACKET_qXfer_loongarch_write, ++ PACKET_qGetTIBAddr, ++ PACKET_qGetTLSAddr, ++ PACKET_qSupported, ++@@ -5154,6 +5156,10 @@ static const struct protocol_feature remote_protocol_features[] = { ++ PACKET_qXfer_threads }, ++ { "qXfer:traceframe-info:read", PACKET_DISABLE, remote_supported_packet, ++ PACKET_qXfer_traceframe_info }, +++ { "qXfer:loongarch:read", PACKET_DISABLE, remote_supported_packet, +++ PACKET_qXfer_loongarch_read }, +++ { "qXfer:loongarch:write", PACKET_DISABLE, remote_supported_packet, +++ PACKET_qXfer_loongarch_write }, ++ { "QPassSignals", PACKET_DISABLE, remote_supported_packet, ++ PACKET_QPassSignals }, ++ { "QCatchSyscalls", PACKET_DISABLE, remote_supported_packet, ++@@ -11013,6 +11019,18 @@ remote_target::xfer_partial (enum target_object object, ++ return TARGET_XFER_E_IO; ++ } ++ +++ if (object == TARGET_OBJECT_LARCH) +++ { +++ if (readbuf) +++ return remote_read_qxfer ("loongarch", annex, readbuf, offset, len, +++ xfered_len, &remote_protocol_packets +++ [PACKET_qXfer_loongarch_read]); +++ else +++ return remote_write_qxfer ("loongarch", annex, writebuf, offset, len, +++ xfered_len, &remote_protocol_packets +++ [PACKET_qXfer_loongarch_write]); +++ } +++ ++ /* Only handle flash writes. */ ++ if (writebuf != NULL) ++ { ++@@ -14626,6 +14644,13 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL, ++ add_packet_config_cmd (&remote_protocol_packets[PACKET_qXfer_uib], ++ "qXfer:uib:read", "unwind-info-block", 0); ++ +++ add_packet_config_cmd (&remote_protocol_packets[PACKET_qXfer_loongarch_read], +++ "qXfer:loongarch:read", "read-loongarch-object", 0); +++ +++ add_packet_config_cmd +++ (&remote_protocol_packets[PACKET_qXfer_loongarch_write], +++ "qXfer:loongarch:write", "write-loongarch-object", 0); +++ ++ add_packet_config_cmd (&remote_protocol_packets[PACKET_qGetTLSAddr], ++ "qGetTLSAddr", "get-thread-local-storage-address", ++ 0); ++diff --git gdb-10.2/gdb/target.h gdb-10.2/gdb/target.h ++index 9603912..40a3cce 100644 ++--- gdb-10.2/gdb/target.h +++++ gdb-10.2/gdb/target.h ++@@ -135,6 +135,9 @@ enum inferior_event_type ++ ++ enum target_object ++ { +++ /* LARCH target specific transfer. See "loongarch-nat.c" "corelow.c" +++ and "remote.c". */ +++ TARGET_OBJECT_LARCH, ++ /* AVR target specific transfer. See "avr-tdep.c" and "remote.c". */ ++ TARGET_OBJECT_AVR, ++ /* Transfer up-to LEN bytes of memory starting at OFFSET. */ ++diff --git gdb-10.2/gdb/testsuite/gdb.base/dump.exp gdb-10.2/gdb/testsuite/gdb.base/dump.exp ++index 2b79237..64d5b39 100644 ++--- gdb-10.2/gdb/testsuite/gdb.base/dump.exp +++++ gdb-10.2/gdb/testsuite/gdb.base/dump.exp ++@@ -143,11 +143,13 @@ make_dump_file "dump srec val [set intarr1.srec] intarray" \ ++ make_dump_file "dump srec val [set intstr1.srec] intstruct" \ ++ "dump struct as value, srec" ++ +++if { ![istarget loongarch*-*-*] } { ++ make_dump_file "dump ihex val [set intarr1.ihex] intarray" \ ++ "dump array as value, intel hex" ++ ++ make_dump_file "dump ihex val [set intstr1.ihex] intstruct" \ ++ "dump struct as value, intel hex" +++} ++ ++ make_dump_file "dump tekhex val [set intarr1.tekhex] intarray" \ ++ "dump array as value, tekhex" ++@@ -244,11 +246,13 @@ make_dump_file "dump srec mem [set intarr2.srec] $array_start $array_end" \ ++ make_dump_file "dump srec mem [set intstr2.srec] $struct_start $struct_end" \ ++ "dump struct as memory, srec" ++ +++if { ![istarget loongarch*-*-*] } { ++ make_dump_file "dump ihex mem [set intarr2.ihex] $array_start $array_end" \ ++ "dump array as memory, ihex" ++ ++ make_dump_file "dump ihex mem [set intstr2.ihex] $struct_start $struct_end" \ ++ "dump struct as memory, ihex" +++} ++ ++ make_dump_file "dump tekhex mem [set intarr2.tekhex] $array_start $array_end" \ ++ "dump array as memory, tekhex" ++diff --git gdb-10.2/gdb/testsuite/gdb.base/float.exp gdb-10.2/gdb/testsuite/gdb.base/float.exp ++index dc5e2fa..d179a8f 100644 ++--- gdb-10.2/gdb/testsuite/gdb.base/float.exp +++++ gdb-10.2/gdb/testsuite/gdb.base/float.exp ++@@ -120,6 +120,8 @@ if { [is_aarch64_target] } then { ++ pass "info float (without FPU)" ++ } ++ } +++} elseif [istarget "loongarch*-*-*"] then { +++ gdb_test "info float" "f.*fcc0.*fcsr.*" "info float" ++ } else { ++ gdb_test "info float" "No floating.point info available for this processor." "info float (unknown target)" ++ } ++diff --git gdb-10.2/gdb/testsuite/gdb.xml/tdesc-regs.exp gdb-10.2/gdb/testsuite/gdb.xml/tdesc-regs.exp ++index 1ee6ae1..4d69fb3 100644 ++--- gdb-10.2/gdb/testsuite/gdb.xml/tdesc-regs.exp +++++ gdb-10.2/gdb/testsuite/gdb.xml/tdesc-regs.exp ++@@ -82,6 +82,11 @@ switch -glob -- [istarget] { ++ set regdir "i386/" ++ set core-regs {64bit-core.xml 64bit-sse.xml} ++ } +++ "loongarch64-*-*" { +++ set architecture "loongarch64" +++ set regdir "loongarch/" +++ set core-regs {base64.xml fpu64.xml lbt64.xml lsx.xml lasx.xml} +++ } ++ } ++ ++ # If no core registers were specified, assume this target does not ++diff --git gdb-10.2/include/dis-asm.h gdb-10.2/include/dis-asm.h ++index 0532cef..b488af0 100644 ++--- gdb-10.2/include/dis-asm.h +++++ gdb-10.2/include/dis-asm.h ++@@ -300,6 +300,7 @@ extern void print_nfp_disassembler_options (FILE *); ++ extern void print_ppc_disassembler_options (FILE *); ++ extern void print_riscv_disassembler_options (FILE *); ++ extern void print_arm_disassembler_options (FILE *); +++extern void print_loongarch_disassembler_options (FILE *); ++ extern void print_arc_disassembler_options (FILE *); ++ extern void print_s390_disassembler_options (FILE *); ++ extern void print_wasm32_disassembler_options (FILE *); ++diff --git gdb-10.2/include/elf/common.h gdb-10.2/include/elf/common.h ++index 571e21a..4aa4a9f 100644 ++--- gdb-10.2/include/elf/common.h +++++ gdb-10.2/include/elf/common.h ++@@ -341,6 +341,7 @@ ++ #define EM_LANAI 244 /* Lanai 32-bit processor. */ ++ #define EM_BPF 247 /* Linux BPF – in-kernel virtual machine. */ ++ #define EM_NFP 250 /* Netronome Flow Processor. */ +++#define EM_LOONGARCH 258 /* LoongArch */ ++ #define EM_CSKY 252 /* C-SKY processor family. */ ++ ++ /* If it is necessary to assign new unofficial EM_* values, please pick large ++@@ -662,6 +663,14 @@ ++ /* note name must be "LINUX". */ ++ #define NT_ARC_V2 0x600 /* ARC HS accumulator/extra registers. */ ++ /* note name must be "LINUX". */ +++#define NT_LARCH_CPUCFG 0x900 /* Loongarch CPU config registers */ +++ /* note name must be "LINUX". */ +++#define NT_LARCH_LBT 0x901 /* Loongarch Loongson Binary Translation registers */ +++ /* note name must be "LINUX". */ +++#define NT_LARCH_LSX 0x902 /* Loongarch Loongson SIMD Extension registers */ +++ /* note name must be "LINUX". */ +++#define NT_LARCH_LASX 0x903 /* Loongarch Loongson Advanced SIMD Extension registers */ +++ /* note name must be "LINUX". */ ++ #define NT_SIGINFO 0x53494749 /* Fields of siginfo_t. */ ++ #define NT_FILE 0x46494c45 /* Description of mapped files. */ ++ ++diff --git gdb-10.2/include/elf/loongarch.h gdb-10.2/include/elf/loongarch.h ++new file mode 100644 ++index 0000000..02085dd ++--- /dev/null +++++ gdb-10.2/include/elf/loongarch.h ++@@ -0,0 +1,95 @@ +++#ifndef _ELF_LOONG_H +++#define _ELF_LOONG_H +++ +++#include +++#include "elf/reloc-macros.h" +++#include "libiberty.h" +++ +++START_RELOC_NUMBERS (elf_loongarch_reloc_type) +++/* used by the dynamic linker */ +++RELOC_NUMBER (R_LARCH_NONE, 0) +++RELOC_NUMBER (R_LARCH_32, 1) +++RELOC_NUMBER (R_LARCH_64, 2) +++RELOC_NUMBER (R_LARCH_RELATIVE, 3) +++RELOC_NUMBER (R_LARCH_COPY, 4) +++RELOC_NUMBER (R_LARCH_JUMP_SLOT, 5) +++RELOC_NUMBER (R_LARCH_TLS_DTPMOD32, 6) +++RELOC_NUMBER (R_LARCH_TLS_DTPMOD64, 7) +++RELOC_NUMBER (R_LARCH_TLS_DTPREL32, 8) +++RELOC_NUMBER (R_LARCH_TLS_DTPREL64, 9) +++RELOC_NUMBER (R_LARCH_TLS_TPREL32, 10) +++RELOC_NUMBER (R_LARCH_TLS_TPREL64, 11) +++RELOC_NUMBER (R_LARCH_IRELATIVE, 12) +++ +++/* Reserved for future relocs that the dynamic linker must understand. */ +++ +++/* used by the static linker for relocating .text */ +++RELOC_NUMBER (R_LARCH_MARK_LA, 20) +++RELOC_NUMBER (R_LARCH_MARK_PCREL, 21) +++ +++/* 这个重定位类型将symbol距离重定位位置的pc相对位置偏移量压栈。 +++ 它against symbol,因为如果是个常数,虽然在no-pic的情况下可以得到结果,但因为 +++ 重定位位置相对这个常数的偏移量一定很大,八成填不进去;而在pic的情况下, +++ 偏移量无法在静态连接时确定。因此我们约定这个重定位不可能against constant */ +++RELOC_NUMBER (R_LARCH_SOP_PUSH_PCREL, 22) +++ +++/* 这个重定位against a symbol or a constant。它将symbol的运行时绝对地址 +++ 或常数压栈,因此在pic的情况下会报错。另外我不太清楚常数和ABS段的关系。 */ +++RELOC_NUMBER (R_LARCH_SOP_PUSH_ABSOLUTE, 23) +++ +++RELOC_NUMBER (R_LARCH_SOP_PUSH_DUP, 24) +++RELOC_NUMBER (R_LARCH_SOP_PUSH_GPREL, 25) +++RELOC_NUMBER (R_LARCH_SOP_PUSH_TLS_TPREL, 26) +++RELOC_NUMBER (R_LARCH_SOP_PUSH_TLS_GOT, 27) +++RELOC_NUMBER (R_LARCH_SOP_PUSH_TLS_GD, 28) +++RELOC_NUMBER (R_LARCH_SOP_PUSH_PLT_PCREL, 29) +++ +++RELOC_NUMBER (R_LARCH_SOP_ASSERT, 30) +++RELOC_NUMBER (R_LARCH_SOP_NOT, 31) +++RELOC_NUMBER (R_LARCH_SOP_SUB, 32) +++RELOC_NUMBER (R_LARCH_SOP_SL, 33) +++RELOC_NUMBER (R_LARCH_SOP_SR, 34) +++RELOC_NUMBER (R_LARCH_SOP_ADD, 35) +++RELOC_NUMBER (R_LARCH_SOP_AND, 36) +++RELOC_NUMBER (R_LARCH_SOP_IF_ELSE, 37) +++RELOC_NUMBER (R_LARCH_SOP_POP_32_S_10_5, 38) +++RELOC_NUMBER (R_LARCH_SOP_POP_32_U_10_12, 39) +++RELOC_NUMBER (R_LARCH_SOP_POP_32_S_10_12, 40) +++RELOC_NUMBER (R_LARCH_SOP_POP_32_S_10_16, 41) +++RELOC_NUMBER (R_LARCH_SOP_POP_32_S_10_16_S2, 42) +++RELOC_NUMBER (R_LARCH_SOP_POP_32_S_5_20, 43) +++RELOC_NUMBER (R_LARCH_SOP_POP_32_S_0_5_10_16_S2, 44) +++RELOC_NUMBER (R_LARCH_SOP_POP_32_S_0_10_10_16_S2, 45) +++RELOC_NUMBER (R_LARCH_SOP_POP_32_U, 46) +++ +++/* used by the static linker for relocating non .text */ +++/* 这几个重定位类型是为了照顾到 ".dword sym1 - sym2" 这种求差的写法。 +++ 这些重定位类型处理的是连接时地址,一般情况下它们是成对出现的。 +++ 在直接求负数".dword - sym1"的情况下,R_LARCH_SUBxx会单独出现。但注意, +++ 那个位置填进去的是连接时地址。 */ +++RELOC_NUMBER (R_LARCH_ADD8, 47) +++RELOC_NUMBER (R_LARCH_ADD16, 48) +++RELOC_NUMBER (R_LARCH_ADD24, 49) +++RELOC_NUMBER (R_LARCH_ADD32, 50) +++RELOC_NUMBER (R_LARCH_ADD64, 51) +++RELOC_NUMBER (R_LARCH_SUB8, 52) +++RELOC_NUMBER (R_LARCH_SUB16, 53) +++RELOC_NUMBER (R_LARCH_SUB24, 54) +++RELOC_NUMBER (R_LARCH_SUB32, 55) +++RELOC_NUMBER (R_LARCH_SUB64, 56) +++ +++/* I don't know what it is. Existing in almost all other arch */ +++RELOC_NUMBER (R_LARCH_GNU_VTINHERIT, 57) +++RELOC_NUMBER (R_LARCH_GNU_VTENTRY, 58) +++ +++END_RELOC_NUMBERS (R_LARCH_count) +++ +++ +++/* Processor specific flags for the ELF header e_flags field. */ +++ +++#define EF_LARCH_ABI 0x0003 +++#define EF_LARCH_ABI_LP64 0x0003 +++#define EF_LARCH_ABI_XLP32 0x0002 +++#define EF_LARCH_ABI_LP32 0x0001 +++ +++#endif /* _ELF_LOONG_H */ ++diff --git gdb-10.2/include/opcode/loongarch.h gdb-10.2/include/opcode/loongarch.h ++new file mode 100644 ++index 0000000..47a9d94 ++--- /dev/null +++++ gdb-10.2/include/opcode/loongarch.h ++@@ -0,0 +1,215 @@ +++#ifndef _LOONGARCH_H_ +++#define _LOONGARCH_H_ +++#include +++ +++#ifdef __cplusplus +++extern "C" { +++#endif +++ +++typedef uint32_t insn_t; +++ +++struct loongarch_opcode +++{ +++ const insn_t match; +++ const insn_t mask; /* High 1 byte is main opcode and it must be 0xf. */ +++#define LARCH_INSN_OPC(insn) ((insn & 0xf0000000) >> 28) +++ const char * const name; +++ +++ /* +++ ACTUAL PARAMETER: +++ +++ // BNF with regular expression. +++args : token* end +++ +++ // just few char separate 'iden' +++token : ',' +++| '(' +++| ')' +++| iden // maybe a label (include at least one alphabet), maybe a number, maybe a expr +++| regname +++ +++regname : '$' iden +++ +++iden : [a-zA-Z0-9\.\+\-]+ +++ +++end : '\0' +++ +++ +++FORMAT: A string to describe the format of actual parameter including bit field infomation. +++For example, "r5:5,r0:5,sr10:16<<2" matches "$12,$13,12345" and "$4,$7,a_label". +++That 'sr' means the instruction may need relocate. '10:16' means bit field of instruction. +++In a 'format', every 'escape's can be replaced to 'iden' or 'regname' acrroding to its meaning. +++We fill all information needed by disassembing and assembing to 'format'. +++ +++ // BNF with regular expression. +++format : escape (literal+ escape)* literal* end +++| (literal+ escape)* literal* end +++ +++end : '\0' // Get here means parse end. +++ +++ // The intersection between any two among FIRST (end), FIRST (literal) and FIRST (escape) must be empty. +++ // So we can build a simple parser. +++literal : ',' +++| '(' +++| ')' +++ +++ // Double '<'s means the real number is the immediate after shifting left. +++escape : esc_ch bit_field '<' '<' dec2 +++| esc_ch bit_field +++| esc_ch // for MACRO. non-macro format must indicate 'bit_field' +++ +++ // '|' means to concatenate nonadjacent bit fields +++ // For example, "10:16|0:4" means +++ // "16 bits starting from the 10th bit concatenating with 4 bits starting from the 0th bit". +++ // This is to say "[25..10]||[3..0]" (little endian). +++b_field : dec2 ':' dec2 +++| dec2 ':' dec2 '|' bit_field +++ +++esc_ch : 's' 'r' // signed immediate or label need relocate +++| 's' // signed immediate no need relocate +++| 'u' // unsigned immediate +++| 'l' // label needed relocate +++| 'r' // general purpose registers +++| 'f' // FPU registers +++| 'v' // 128 bit SIMD register +++| 'x' // 256 bit SIMD register +++ +++dec2 : [1-9][0-9]? +++| 0 +++ +++*/ +++ const char * const format; +++ +++ /* +++MACRO: Indicate how a macro instruction expand for assembling. +++The main is to replace the '%num'(means the 'num'th 'escape' in 'format') in 'macro' string to get the real instruction. +++As for marco insn "b" in MIPS, we can say its name is "b", format is "l", macro is "j %1". So "b 3f" will be expanded to "j 3f". +++As for marco insn "li" in MIPS, we can say its name is "li", format is "s", macro is "ori" +++ +++ +++Maybe need +++*/ +++ const char * const macro; +++ const int *include; +++ const int *exclude; +++ +++ const unsigned long pinfo; +++#define USELESS 0x0l +++ +++}; +++ +++struct hash_control; +++ +++struct loongarch_ase +++{ +++ const int *enabled; +++ struct loongarch_opcode * const opcodes; +++ const int *include; +++ const int *exclude; +++ +++ /* for disassemble to create main opcode hash table. */ +++ const struct loongarch_opcode *opc_htab[16]; +++ unsigned char opc_htab_inited; +++ +++ /* for GAS to create hash table. */ +++ struct hash_control *name_hash_entry; +++}; +++ +++extern int is_unsigned (const char *); +++extern int is_signed (const char *); +++extern int is_branch_label (const char *); +++ +++extern int +++loongarch_get_bit_field_width (const char *bit_field, char **end); +++extern int32_t +++loongarch_decode_imm (const char *bit_field, insn_t insn, int si); +++ +++#define MAX_ARG_NUM_PLUS_2 9 +++ +++extern size_t +++loongarch_split_args_by_comma (char *args, const char *arg_strs[]); +++extern char * +++loongarch_cat_splited_strs (const char *arg_strs[]); +++extern insn_t +++loongarch_foreach_args (const char *format, const char *arg_strs[], +++ int32_t (*helper) (char esc1, char esc2, +++ const char *bit_field, +++ const char *arg, void *context), +++ void *context); +++ +++extern int +++loongarch_check_format (const char *format); +++extern int +++loongarch_check_macro (const char *format, const char *macro); +++ +++extern char * +++loongarch_expand_macro_with_format_map (const char *format, const char *macro, +++ const char * const arg_strs[], +++ const char * (*map) ( +++ char esc1, char esc2, +++ const char *arg), +++ char * (*helper) ( +++ const char * const arg_strs[], +++ void *context), +++ void *context); +++extern char * +++loongarch_expand_macro (const char *macro, const char * const arg_strs[], +++ char * (*helper) (const char * const arg_strs[], +++ void *context), +++ void *context); +++extern size_t +++loongarch_bits_imm_needed (int64_t imm, int si); +++ +++/* 将字符串中指定的连续字符化为1个 */ +++extern void +++loongarch_eliminate_adjacent_repeat_char (char *dest, char c); +++ +++/* 下面两个函数计划作为libopcode.a拿出来给一些系统软件反汇编用 */ +++extern int +++loongarch_parse_dis_options (const char *opts_in); +++extern void +++loongarch_disassemble_one (int64_t pc, insn_t insn, +++ int (*fprintf_func) +++ (void *stream, const char *format, ...), +++ void *stream); +++ +++extern const char * const loongarch_r_normal_name[32]; +++extern const char * const loongarch_r_lp64_name[32]; +++extern const char * const loongarch_r_lp64_name1[32]; +++extern const char * const loongarch_f_normal_name[32]; +++extern const char * const loongarch_f_lp64_name[32]; +++extern const char * const loongarch_f_lp64_name1[32]; +++extern const char * const loongarch_c_normal_name[8]; +++extern const char * const loongarch_cr_normal_name[4]; +++extern const char * const loongarch_v_normal_name[32]; +++extern const char * const loongarch_x_normal_name[32]; +++ +++extern struct loongarch_ase loongarch_ASEs[]; +++ +++extern struct loongarch_ASEs_option +++{ +++ int ase_test; +++ int ase_fix; +++ int ase_float; +++ int ase_128vec; +++ int ase_256vec; +++ +++ int addrwidth_is_32; +++ int addrwidth_is_64; +++ int rlen_is_32; +++ int rlen_is_64; +++ int la_local_with_abs; +++ int la_global_with_pcrel; +++ int la_global_with_abs; +++ +++ int abi_is_lp32; +++ int abi_is_lp64; +++} LARCH_opts; +++ +++extern size_t loongarch_insn_length (insn_t insn); +++ +++#ifdef __cplusplus +++} +++#endif +++ +++#endif /* _LOONGARCH_H_ */ ++diff --git gdb-10.2/opcodes/Makefile.am gdb-10.2/opcodes/Makefile.am ++index 7318bf0..c964ee1 100644 ++--- gdb-10.2/opcodes/Makefile.am +++++ gdb-10.2/opcodes/Makefile.am ++@@ -162,6 +162,9 @@ TARGET_LIBOPCODES_CFILES = \ ++ lm32-ibld.c \ ++ lm32-opc.c \ ++ lm32-opinst.c \ +++ loongarch-opc.c \ +++ loongarch-dis.c \ +++ loongarch-coder.c \ ++ m10200-dis.c \ ++ m10200-opc.c \ ++ m10300-dis.c \ ++diff --git gdb-10.2/opcodes/Makefile.in gdb-10.2/opcodes/Makefile.in ++index ddb9346..b1cb50a 100644 ++--- gdb-10.2/opcodes/Makefile.in +++++ gdb-10.2/opcodes/Makefile.in ++@@ -552,6 +552,9 @@ TARGET_LIBOPCODES_CFILES = \ ++ lm32-ibld.c \ ++ lm32-opc.c \ ++ lm32-opinst.c \ +++ loongarch-opc.c \ +++ loongarch-dis.c \ +++ loongarch-coder.c \ ++ m10200-dis.c \ ++ m10200-opc.c \ ++ m10300-dis.c \ ++@@ -966,6 +969,9 @@ distclean-compile: ++ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lm32-ibld.Plo@am__quote@ ++ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lm32-opc.Plo@am__quote@ ++ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lm32-opinst.Plo@am__quote@ +++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/loongarch-dis.Plo@am__quote@ +++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/loongarch-opc.Plo@am__quote@ +++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/loongarch-coder.Plo@am__quote@ ++ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m10200-dis.Plo@am__quote@ ++ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m10200-opc.Plo@am__quote@ ++ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m10300-dis.Plo@am__quote@ ++diff --git gdb-10.2/opcodes/configure gdb-10.2/opcodes/configure ++index e448c9e..22c35cf 100755 ++--- gdb-10.2/opcodes/configure +++++ gdb-10.2/opcodes/configure ++@@ -12890,6 +12890,7 @@ if test x${all_targets} = xfalse ; then ++ bfd_epiphany_arch) ta="$ta epiphany-asm.lo epiphany-desc.lo epiphany-dis.lo epiphany-ibld.lo epiphany-opc.lo" using_cgen=yes ;; ++ bfd_iq2000_arch) ta="$ta iq2000-asm.lo iq2000-desc.lo iq2000-dis.lo iq2000-ibld.lo iq2000-opc.lo" using_cgen=yes ;; ++ bfd_lm32_arch) ta="$ta lm32-asm.lo lm32-desc.lo lm32-dis.lo lm32-ibld.lo lm32-opc.lo lm32-opinst.lo" using_cgen=yes ;; +++ bfd_loongarch_arch) ta="$ta loongarch-dis.lo loongarch-opc.lo loongarch-coder.lo" ;; ++ bfd_m32c_arch) ta="$ta m32c-asm.lo m32c-desc.lo m32c-dis.lo m32c-ibld.lo m32c-opc.lo" using_cgen=yes ;; ++ bfd_m32r_arch) ta="$ta m32r-asm.lo m32r-desc.lo m32r-dis.lo m32r-ibld.lo m32r-opc.lo m32r-opinst.lo" using_cgen=yes ;; ++ bfd_m68hc11_arch) ta="$ta m68hc11-dis.lo m68hc11-opc.lo" ;; ++diff --git gdb-10.2/opcodes/configure.ac gdb-10.2/opcodes/configure.ac ++index 00be9c8..6972477 100644 ++--- gdb-10.2/opcodes/configure.ac +++++ gdb-10.2/opcodes/configure.ac ++@@ -281,6 +281,7 @@ if test x${all_targets} = xfalse ; then ++ bfd_epiphany_arch) ta="$ta epiphany-asm.lo epiphany-desc.lo epiphany-dis.lo epiphany-ibld.lo epiphany-opc.lo" using_cgen=yes ;; ++ bfd_iq2000_arch) ta="$ta iq2000-asm.lo iq2000-desc.lo iq2000-dis.lo iq2000-ibld.lo iq2000-opc.lo" using_cgen=yes ;; ++ bfd_lm32_arch) ta="$ta lm32-asm.lo lm32-desc.lo lm32-dis.lo lm32-ibld.lo lm32-opc.lo lm32-opinst.lo" using_cgen=yes ;; +++ bfd_loongarch_arch) ta="$ta loongarch-dis.lo loongarch-opc.lo loongarch-coder.lo" ;; ++ bfd_m32c_arch) ta="$ta m32c-asm.lo m32c-desc.lo m32c-dis.lo m32c-ibld.lo m32c-opc.lo" using_cgen=yes ;; ++ bfd_m32r_arch) ta="$ta m32r-asm.lo m32r-desc.lo m32r-dis.lo m32r-ibld.lo m32r-opc.lo m32r-opinst.lo" using_cgen=yes ;; ++ bfd_m68hc11_arch) ta="$ta m68hc11-dis.lo m68hc11-opc.lo" ;; ++diff --git gdb-10.2/opcodes/disassemble.c gdb-10.2/opcodes/disassemble.c ++index 290dcdd..61e24bc 100644 ++--- gdb-10.2/opcodes/disassemble.c +++++ gdb-10.2/opcodes/disassemble.c ++@@ -49,6 +49,7 @@ ++ #define ARCH_ip2k ++ #define ARCH_iq2000 ++ #define ARCH_lm32 +++#define ARCH_loongarch ++ #define ARCH_m32c ++ #define ARCH_m32r ++ #define ARCH_m68hc11 ++@@ -261,6 +262,11 @@ disassembler (enum bfd_architecture a, ++ disassemble = print_insn_lm32; ++ break; ++ #endif +++#ifdef ARCH_loongarch +++ case bfd_arch_loongarch: +++ disassemble = print_insn_loongarch; +++ break; +++#endif ++ #ifdef ARCH_m32r ++ case bfd_arch_m32r: ++ disassemble = print_insn_m32r; ++@@ -591,6 +597,9 @@ disassembler_usage (FILE *stream ATTRIBUTE_UNUSED) ++ #ifdef ARCH_wasm32 ++ print_wasm32_disassembler_options (stream); ++ #endif +++#ifdef ARCH_loongarch +++ print_loongarch_disassembler_options (stream); +++#endif ++ ++ return; ++ } ++diff --git gdb-10.2/opcodes/disassemble.h gdb-10.2/opcodes/disassemble.h ++index 89db886..a490ed9 100644 ++--- gdb-10.2/opcodes/disassemble.h +++++ gdb-10.2/opcodes/disassemble.h ++@@ -58,6 +58,7 @@ extern int print_insn_little_mips (bfd_vma, disassemble_info *); ++ extern int print_insn_little_powerpc (bfd_vma, disassemble_info *); ++ extern int print_insn_little_score (bfd_vma, disassemble_info *); ++ extern int print_insn_lm32 (bfd_vma, disassemble_info *); +++extern int print_insn_loongarch (bfd_vma, disassemble_info *); ++ extern int print_insn_m32r (bfd_vma, disassemble_info *); ++ extern int print_insn_m68hc11 (bfd_vma, disassemble_info *); ++ extern int print_insn_m68hc12 (bfd_vma, disassemble_info *); ++diff --git gdb-10.2/opcodes/loongarch-coder.c gdb-10.2/opcodes/loongarch-coder.c ++new file mode 100644 ++index 0000000..399af4f ++--- /dev/null +++++ gdb-10.2/opcodes/loongarch-coder.c ++@@ -0,0 +1,446 @@ +++#include "sysdep.h" +++#include "opcode/loongarch.h" +++ +++int +++is_unsigned (const char *c_str) +++{ +++ if (c_str[0] == '0' && (c_str[1] == 'x' || c_str[1] == 'X')) +++ { +++ c_str += 2; +++ while (('a' <= *c_str && *c_str <= 'f') +++ || ('A' <= *c_str && *c_str <= 'F') +++ || ('0' <= *c_str && *c_str <= '9')) +++ c_str++; +++ } +++ else if (*c_str == '\0') +++ return 0; +++ else +++ while ('0' <= *c_str && *c_str <= '9') +++ c_str++; +++ return *c_str == '\0'; +++} +++ +++int +++is_signed (const char *c_str) +++{ +++ return *c_str == '-' ? is_unsigned (c_str + 1) : is_unsigned (c_str); +++} +++ +++int +++loongarch_get_bit_field_width (const char *bit_field, char **end) +++{ +++ int width = 0; +++ char has_specify = 0, *bit_field_1 = (char *) bit_field; +++ if (bit_field_1 && *bit_field_1 != '\0') +++ while (1) +++ { +++ strtol (bit_field_1, &bit_field_1, 10); +++ +++ if (*bit_field_1 != ':') +++ break; +++ bit_field_1++; +++ +++ width += strtol (bit_field_1, &bit_field_1, 10); +++ has_specify = 1; +++ +++ if (*bit_field_1 != '|') +++ break; +++ bit_field_1++; +++ } +++ if (end) +++ *end = bit_field_1; +++ return has_specify ? width : -1; +++} +++ +++int32_t +++loongarch_decode_imm (const char *bit_field, insn_t insn, int si) +++{ +++ int32_t ret = 0; +++ uint32_t t; +++ int len = 0, width, b_start; +++ char *bit_field_1 = (char *) bit_field; +++ while (1) +++ { +++ b_start = strtol (bit_field_1, &bit_field_1, 10); +++ if (*bit_field_1 != ':') +++ break; +++ width = strtol (bit_field_1 + 1, &bit_field_1, 10); +++ len += width; +++ +++ t = insn; +++ t <<= sizeof (t) * 8 - width - b_start; +++ t >>= sizeof (t) * 8 - width; +++ ret <<= width; +++ ret |= t; +++ +++ if (*bit_field_1 != '|') +++ break; +++ bit_field_1++; +++ } +++ +++ if (*bit_field_1 == '<' && *(++bit_field_1) == '<') +++ { +++ width = atoi(bit_field_1 + 1); +++ ret <<= width; +++ len += width; +++ } +++ else if (*bit_field_1 == '+') +++ ret += atoi(bit_field_1 + 1); +++ +++ if (si) +++ { +++ ret <<= sizeof (ret) * 8 - len; +++ ret >>= sizeof (ret) * 8 - len; +++ } +++ return ret; +++} +++ +++static insn_t +++loongarch_encode_imm (const char *bit_field, int32_t imm) +++{ +++ char *bit_field_1 = (char *) bit_field; +++ char *t = bit_field_1; +++ int width, b_start; +++ insn_t ret = 0, i; +++ +++ width = loongarch_get_bit_field_width (t, &t); +++ if (width == -1) +++ return ret; +++ +++ if (*t == '<' && *(++t) == '<') +++ width += atoi (t + 1); +++ else if (*t == '+') +++ imm -= atoi (t + 1); +++ +++ imm <<= sizeof (imm) * 8 - width; +++ while (1) +++ { +++ b_start = strtol (bit_field_1, &bit_field_1, 10); +++ if (*bit_field_1 != ':') +++ break; +++ width = strtol (bit_field_1 + 1, &bit_field_1, 10); +++ i = imm; +++ i >>= sizeof (i) * 8 - width; +++ i <<= b_start; +++ ret |= i; +++ imm <<= width; +++ +++ if (*bit_field_1 != '|') +++ break; +++ bit_field_1++; +++ } +++ return ret; +++} +++ +++/* parse such FORMAT +++ "" +++ "u" +++ "v0:5,r5:5,s10:10<<2" +++ "r0:5,r5:5,r10:5,u15:2+1" +++ "r,r,u0:5+32,u0:5+1" +++*/ +++static int +++loongarch_parse_format (const char *format, +++ char *esc1s, char *esc2s, const char **bit_fields) +++{ +++ size_t arg_num = 0; +++ +++ if (*format == '\0') +++ goto end; +++ +++ while (1) +++ { +++ /* esc1 esc2 +++ for "[a-zA-Z][a-zA-Z]?" */ +++ if (('a' <= *format && *format <= 'z') +++ || ('A' <= *format && *format <= 'Z')) +++ { +++ *esc1s++ = *format++; +++ if (('a' <= *format && *format <= 'z') +++ || ('A' <= *format && *format <= 'Z')) +++ *esc2s++ = *format++; +++ else +++ *esc2s++ = '\0'; +++ } +++ else +++ return -1; +++ +++ arg_num++; +++ if (MAX_ARG_NUM_PLUS_2 - 2 < arg_num) +++ /* need larger MAX_ARG_NUM_PLUS_2 */ +++ return -1; +++ +++ *bit_fields++ = format; +++ +++ if ('0' <= *format && *format <= '9') +++ { +++ /* for "[0-9]+:[0-9]+(\|[0-9]+:[0-9]+)*" */ +++ while (1) +++ { +++ while ('0' <= *format && *format <= '9') +++ format++; +++ +++ if (*format != ':') +++ return -1; +++ format++; +++ +++ if (!('0' <= *format && *format <= '9')) +++ return -1; +++ while ('0' <= *format && *format <= '9') +++ format++; +++ +++ if (*format != '|') +++ break; +++ format++; +++ } +++ +++ /* for "((\+|<<)[1-9][0-9]*)?" */ +++ do +++ { +++ if (*format == '+') +++ format++; +++ else if (format[0] == '<' && format[1] == '<') +++ format += 2; +++ else +++ break; +++ +++ if (!('1' <= *format && *format <= '9')) +++ return -1; +++ while ('0' <= *format && *format <= '9') +++ format++; +++ } +++ while (0); +++ } +++ +++ if (*format == ',') +++ format++; +++ else if (*format == '\0') +++ break; +++ else +++ return -1; +++ } +++ +++end: +++ *esc1s = '\0'; +++ return 0; +++} +++ +++size_t +++loongarch_split_args_by_comma (char *args, const char * arg_strs[]) +++{ +++ size_t num = 0; +++ +++ if (*args) +++ arg_strs[num++] = args; +++ for (; *args; args++) +++ if (*args == ',') +++ { +++ if (MAX_ARG_NUM_PLUS_2 - 1 == num) +++ break; +++ else +++ *args = '\0', arg_strs[num++] = args + 1; +++ } +++ arg_strs[num] = NULL; +++ return num; +++} +++ +++char * +++loongarch_cat_splited_strs (const char *arg_strs[]) +++{ +++ char *ret; +++ size_t n, l; +++ +++ for (l = 0, n = 0; arg_strs[n]; n++) +++ l += strlen (arg_strs[n]); +++ ret = malloc (l + n + 1); +++ ret[0] = '\0'; +++ if (0 < n) +++ strcat (ret, arg_strs[0]); +++ for (l = 1; l < n; l++) +++ strcat (ret, ","), strcat (ret, arg_strs[l]); +++ return ret; +++} +++ +++insn_t +++loongarch_foreach_args (const char *format, const char *arg_strs[], +++ int32_t (*helper) (char esc1, char esc2, +++ const char *bit_field, +++ const char *arg, void *context), +++ void *context) +++{ +++ char esc1s[MAX_ARG_NUM_PLUS_2 - 1], esc2s[MAX_ARG_NUM_PLUS_2 - 1]; +++ const char *bit_fields[MAX_ARG_NUM_PLUS_2 - 1]; +++ size_t i; +++ insn_t ret = 0; +++ int ok; +++ +++ ok = loongarch_parse_format (format, esc1s, esc2s, bit_fields) == 0; +++ +++ /* make sure the num of actual args is equal to the num of escape */ +++ for (i = 0; esc1s[i] && arg_strs[i]; i++); +++ ok = ok && !esc1s[i] && !arg_strs[i]; +++ +++ if (ok && helper) +++ { +++ for (i = 0; arg_strs[i]; i++) +++ ret |= loongarch_encode_imm (bit_fields[i], +++ helper (esc1s[i], esc2s[i], bit_fields[i], +++ arg_strs[i], context)); +++ ret |= helper ('\0', '\0', NULL, NULL, context); +++ } +++ +++ return ret; +++} +++ +++int +++loongarch_check_format (const char *format) +++{ +++ char esc1s[MAX_ARG_NUM_PLUS_2 - 1], esc2s[MAX_ARG_NUM_PLUS_2 - 1]; +++ const char *bit_fields[MAX_ARG_NUM_PLUS_2 - 1]; +++ +++ if (!format) +++ return -1; +++ +++ return loongarch_parse_format (format, esc1s, esc2s, bit_fields); +++} +++ +++int +++loongarch_check_macro (const char *format, const char *macro) +++{ +++ int num_of_args; +++ char esc1s[MAX_ARG_NUM_PLUS_2 - 1], esc2s[MAX_ARG_NUM_PLUS_2 - 1]; +++ const char *bit_fields[MAX_ARG_NUM_PLUS_2 - 1]; +++ +++ if (!format || !macro +++ || loongarch_parse_format (format, esc1s, esc2s, bit_fields) != 0) +++ return -1; +++ +++ for (num_of_args = 0; esc1s[num_of_args]; num_of_args++); +++ +++ for (; macro[0]; macro++) +++ if (macro[0] == '%') +++ { +++ macro++; +++ if ('1' <= macro[0] && macro[0] <= '9') +++ { +++ if (num_of_args < macro[0] - '0') +++ /* out of args num */ +++ return -1; +++ } +++ else if (macro[0] == 'f'); +++ else if (macro[0] == '%'); +++ else +++ return -1; +++ } +++ return 0; +++} +++ +++static const char * +++I (char esc_ch1 ATTRIBUTE_UNUSED, +++ char esc_ch2 ATTRIBUTE_UNUSED, +++ const char *c_str) +++{ +++ return c_str; +++} +++ +++char * +++loongarch_expand_macro_with_format_map (const char *format, const char *macro, +++ const char * const arg_strs[], +++ const char * (*map) ( +++ char esc1, char esc2, +++ const char *arg), +++ char * (*helper) ( +++ const char * const arg_strs[], +++ void *context), +++ void *context) +++{ +++ char esc1s[MAX_ARG_NUM_PLUS_2 - 1], esc2s[MAX_ARG_NUM_PLUS_2 - 1]; +++ const char *bit_fields[MAX_ARG_NUM_PLUS_2 - 1]; +++ const char *src; +++ char *dest; +++ char buffer[8192]; +++ +++ if (format) +++ loongarch_parse_format (format, esc1s, esc2s, bit_fields); +++ +++ src = macro; +++ dest = buffer; +++ +++ while (*src) +++ if (*src == '%') +++ { +++ src++; +++ if ('1' <= *src && *src <= '9') +++ { +++ size_t i = *src - '1'; +++ const char *t = map (esc1s[i], esc2s[i], arg_strs[i]); +++ while (*t) +++ *dest++ = *t++; +++ } +++ else if (*src == '%') +++ *dest++ = '%'; +++ else if (*src == 'f' && helper) +++ { +++ char *b, *t; +++ t = b = (*helper) (arg_strs, context); +++ if (b) +++ { +++ while (*t) +++ *dest++ = *t++; +++ free (b); +++ } +++ } +++ src++; +++ } +++ else +++ *dest++ = *src++; +++ +++ *dest = '\0'; +++ return strdup (buffer); +++} +++ +++char * +++loongarch_expand_macro (const char *macro, const char * const arg_strs[], +++ char * (*helper) (const char * const arg_strs[], +++ void *context), +++ void *context) +++{ +++ return loongarch_expand_macro_with_format_map +++ (NULL, macro, arg_strs, I, helper, context); +++} +++ +++size_t +++loongarch_bits_imm_needed (int64_t imm, int si) +++{ +++ size_t ret; +++ if (si) +++ { +++ if (imm < 0) +++ { +++ for (ret = 0; imm < 0; imm <<= 1, ret++); +++ ret = 64 - ret + 1; +++ } +++ else +++ ret = loongarch_bits_imm_needed (imm, 0) + 1; +++ } +++ else +++ { +++ uint64_t t = imm; +++ for (ret = 0; t; t >>= 1, ret++); +++ } +++ return ret; +++} +++ +++void +++loongarch_eliminate_adjacent_repeat_char (char *dest, char c) +++{ +++ if (c == '\0') +++ return; +++ char *src = dest; +++ while (*dest) +++ { +++ while (src[0] == c && src[0] == src[1]) +++ src++; +++ *dest++ = *src++; +++ } +++} ++diff --git gdb-10.2/opcodes/loongarch-dis.c gdb-10.2/opcodes/loongarch-dis.c ++new file mode 100644 ++index 0000000..888c55f ++--- /dev/null +++++ gdb-10.2/opcodes/loongarch-dis.c ++@@ -0,0 +1,311 @@ +++#include "sysdep.h" +++#include "disassemble.h" +++#include "opintl.h" +++#include "opcode/loongarch.h" +++#include +++ +++static const struct loongarch_opcode * +++get_loongarch_opcode_by_binfmt (insn_t insn) +++{ +++ const struct loongarch_opcode *it; +++ struct loongarch_ase *ase; +++ size_t i; +++ for (ase = loongarch_ASEs; ase->enabled; ase++) +++ { +++ if (!*ase->enabled +++ || (ase->include && !*ase->include) +++ || (ase->exclude && *ase->exclude)) +++ continue; +++ +++ if (!ase->opc_htab_inited) +++ { +++ for (it = ase->opcodes; it->mask; it++) +++ if (!ase->opc_htab[LARCH_INSN_OPC (it->match)] +++ && it->macro == NULL) +++ ase->opc_htab[LARCH_INSN_OPC (it->match)] = it; +++ for (i = 0; i < 16; i++) +++ if (!ase->opc_htab[i]) +++ ase->opc_htab[i] = it; +++ ase->opc_htab_inited = 1; +++ } +++ +++ it = ase->opc_htab[LARCH_INSN_OPC(insn)]; +++ for (; it->name; it++) +++ if ((insn & it->mask) == it->match +++ && it->mask +++ && !(it->include && !*it->include) +++ && !(it->exclude && *it->exclude)) +++ return it; +++ } +++ return NULL; +++} +++ +++static const char * const *loongarch_r_disname = NULL; +++static const char * const *loongarch_f_disname = NULL; +++static const char * const *loongarch_c_disname = NULL; +++static const char * const *loongarch_cr_disname = NULL; +++static const char * const *loongarch_v_disname = NULL; +++static const char * const *loongarch_x_disname = NULL; +++ +++static void +++set_default_loongarch_dis_options (void) +++{ +++ LARCH_opts.ase_test = 1; +++ LARCH_opts.ase_fix = 1; +++ LARCH_opts.ase_float = 1; +++ LARCH_opts.ase_128vec = 1; +++ LARCH_opts.ase_256vec = 1; +++ +++ loongarch_r_disname = loongarch_r_normal_name; +++ loongarch_f_disname = loongarch_f_normal_name; +++ loongarch_c_disname = loongarch_c_normal_name; +++ loongarch_cr_disname = loongarch_cr_normal_name; +++ loongarch_v_disname = loongarch_v_normal_name; +++ loongarch_x_disname = loongarch_x_normal_name; +++} +++ +++static int +++parse_loongarch_dis_option (const char *option ATTRIBUTE_UNUSED) +++{ +++ return -1; +++} +++ +++static int +++parse_loongarch_dis_options (const char *opts_in) +++{ +++ set_default_loongarch_dis_options (); +++ +++ if (opts_in == NULL) +++ return 0; +++ +++ char opts[strlen (opts_in) + 1], *opt, *opt_end; +++ strcpy (opts, opts_in); +++ +++ for (opt = opt_end = opts; opt_end != NULL; opt = opt_end + 1) +++ { +++ if ((opt_end = strchr (opt, ',')) != NULL) +++ *opt_end = 0; +++ if (parse_loongarch_dis_option (opt) != 0) +++ return -1; +++ } +++ return 0; +++} +++ +++static int32_t +++dis_one_arg (char esc1, char esc2, const char *bit_field, +++ const char *arg ATTRIBUTE_UNUSED, void *context) +++{ +++ static int need_comma = 0; +++ struct disassemble_info *info = context; +++ insn_t insn = *(insn_t *) info->private_data; +++ int32_t imm, u_imm; +++ +++ if (esc1) +++ { +++ if (need_comma) +++ info->fprintf_func (info->stream, ","); +++ need_comma = 1; +++ imm = loongarch_decode_imm (bit_field, insn, 1); +++ u_imm = loongarch_decode_imm (bit_field, insn, 0); +++ } +++ +++ switch (esc1) +++ { +++ case 'r': +++ info->fprintf_func (info->stream, "%s", loongarch_r_disname[u_imm]); +++ break; +++ case 'f': +++ info->fprintf_func (info->stream, "%s", loongarch_f_disname[u_imm]); +++ break; +++ case 'c': +++ switch (esc2) +++ { +++ case 'r': +++ info->fprintf_func (info->stream, "%s", loongarch_cr_disname[u_imm]); +++ break; +++ default: +++ info->fprintf_func (info->stream, "%s", loongarch_c_disname[u_imm]); +++ } +++ break; +++ case 'v': +++ info->fprintf_func (info->stream, "%s", loongarch_v_disname[u_imm]); +++ break; +++ case 'x': +++ info->fprintf_func (info->stream, "%s", loongarch_x_disname[u_imm]); +++ break; +++ case 'u': +++ info->fprintf_func (info->stream, "0x%x", u_imm); +++ break; +++ case 's': +++ if (imm == 0) +++ info->fprintf_func (info->stream, "%d", imm); +++ else +++ info->fprintf_func (info->stream, "%d(0x%x)", imm, u_imm); +++ switch (esc2) +++ { +++ case 'b': +++ info->insn_type = dis_branch; +++ info->target += imm; +++ } +++ break; +++ case '\0': +++ need_comma = 0; +++ } +++ return 0; +++} +++ +++static void +++disassemble_one (insn_t insn, struct disassemble_info *info) +++{ +++ const struct loongarch_opcode *opc = get_loongarch_opcode_by_binfmt (insn); +++ +++#ifdef LOONGARCH_DEBUG +++ char have_space[32] = {0}; +++ insn_t t; +++ int i; +++ const char *t_f = opc ? opc->format : NULL; +++ if(t_f) +++ while (*t_f) +++ { +++ while (('a' <= t_f[0] && t_f[0] <= 'z') +++ || ('A' <= t_f[0] && t_f[0] <= 'Z') +++ t_f[0] == ',') +++ t_f++; +++ while (1) +++ { +++ i = strtol (t_f, &t_f, 10); +++ have_space[i] = 1; +++ t_f++; //':' +++ i += strtol (t_f, &t_f, 10); +++ have_space[i] = 1; +++ if (t_f[0] == '|') +++ t_f++; +++ else +++ break; +++ } +++ if (t_f[0] == '<') +++ t_f += 2; // '<' '<' +++ strtol (t_f, &t_f, 10); +++ } +++ +++ have_space[28] = 1; +++ have_space[0] = 0; +++ t = ~((insn_t)-1 >> 1); +++ for (i = 31; 0 <= i ; i--) +++ { +++ if (t & insn) +++ info->fprintf_func (info->stream, "1"); +++ else +++ info->fprintf_func (info->stream, "0"); +++ if (have_space[i]) +++ info->fprintf_func (info->stream, " "); +++ t = t >> 1; +++ } +++ info->fprintf_func (info->stream, "\t"); +++#endif +++ +++ if (!opc) +++ { +++ info->insn_type = dis_noninsn; +++ info->fprintf_func (info->stream, "0x%08x", insn); +++ return; +++ } +++ +++ info->insn_type = dis_nonbranch; +++ info->fprintf_func (info->stream, "%s", opc->name); +++ +++ { +++ char fake_args[strlen (opc->format) + 1]; +++ const char *fake_arg_strs[MAX_ARG_NUM_PLUS_2]; +++ strcpy (fake_args, opc->format); +++ if (0 < loongarch_split_args_by_comma (fake_args, fake_arg_strs)) +++ info->fprintf_func (info->stream, "\t"); +++ info->private_data = &insn; +++ loongarch_foreach_args (opc->format, fake_arg_strs, dis_one_arg, info); +++ } +++ +++ if (info->insn_type == dis_branch || info->insn_type == dis_condbranch +++ /* || someother if we have extra info to print */) +++ info->fprintf_func (info->stream, " #"); +++ +++ if (info->insn_type == dis_branch || info->insn_type == dis_condbranch) +++ { +++ info->fprintf_func (info->stream, " "); +++ info->print_address_func (info->target, info); +++ } +++} +++ +++int +++print_insn_loongarch (bfd_vma memaddr, struct disassemble_info *info) +++{ +++ insn_t insn; +++ int status; +++ +++ static int not_init_yet = 1; +++ if (not_init_yet) +++ { +++ parse_loongarch_dis_options (info->disassembler_options); +++ not_init_yet = 0; +++ } +++ +++ info->bytes_per_chunk = 4; +++ info->bytes_per_line = 4; +++ info->display_endian = BFD_ENDIAN_LITTLE; +++ info->insn_info_valid = 1; +++ info->target = memaddr; +++ +++ if ((status = info->read_memory_func +++ (memaddr, (bfd_byte *) &insn, sizeof (insn), info)) +++ != 0) +++ { +++ info->memory_error_func (status, memaddr, info); +++ return -1; //loongarch_insn_length (0); +++ } +++ +++ disassemble_one (insn, info); +++ +++ return loongarch_insn_length (insn); +++} +++ +++void +++print_loongarch_disassembler_options (FILE *stream) +++{ +++ fprintf (stream, _("\n\ +++ LoongISA:\n")); +++ +++ fprintf (stream, _("\n")); +++} +++ +++int +++loongarch_parse_dis_options (const char *opts_in) +++{ +++ return parse_loongarch_dis_options (opts_in); +++} +++ +++static void +++my_print_address_func (bfd_vma addr, struct disassemble_info *dinfo) +++{ +++ dinfo->fprintf_func (dinfo->stream, "0x%llx", (long long) addr); +++} +++ +++void +++loongarch_disassemble_one (int64_t pc, insn_t insn, +++ int (*fprintf_func) +++ (void *stream, const char *format, ...), +++ void *stream) +++{ +++ static struct disassemble_info my_disinfo = { +++ .print_address_func = my_print_address_func, +++ }; +++ static int not_init_yet = 1; +++ if (not_init_yet) +++ { +++ loongarch_parse_dis_options (NULL); +++ not_init_yet = 0; +++ } +++ +++ my_disinfo.fprintf_func = fprintf_func; +++ my_disinfo.stream = stream; +++ my_disinfo.target = pc; +++ disassemble_one (insn, &my_disinfo); +++} ++diff --git gdb-10.2/opcodes/loongarch-opc.c gdb-10.2/opcodes/loongarch-opc.c ++new file mode 100644 ++index 0000000..fb36e56 ++--- /dev/null +++++ gdb-10.2/opcodes/loongarch-opc.c ++@@ -0,0 +1,2152 @@ +++#include +++#include "opcode/loongarch.h" +++ +++struct loongarch_ASEs_option LARCH_opts = +++{ +++ .ase_test = 0, +++ .ase_fix = 0, +++ .ase_float = 0, +++ .ase_128vec = 0, +++ .ase_256vec = 0, +++ +++ .addrwidth_is_32 = 0, +++ .addrwidth_is_64 = 0, +++ .rlen_is_32 = 0, +++ .rlen_is_64 = 0, +++ .la_local_with_abs = 0, +++ .la_global_with_pcrel = 0, +++ .la_global_with_abs = 0, +++ +++ .abi_is_lp32 = 0, +++ .abi_is_lp64 = 0, +++}; +++ +++/* 预留。按理来说应该传入足够的信息使得这个函数可以返回指令长度 */ +++size_t loongarch_insn_length (insn_t insn) +++{ +++ return insn ? 4 : 4; /* eliminate warning */ +++} +++ +++const char * const loongarch_r_normal_name[32] = +++{ +++ "$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", "$r28", "$r29", "$r30", "$r31", +++}; +++ +++const char * const loongarch_r_lp64_name[32] = +++{ +++ "$zero", "$ra", "$tp", "$sp", "$a0", "$a1", "$a2", "$a3", +++ "$a4", "$a5", "$a6", "$a7", "$t0", "$t1", "$t2", "$t3", +++ "$t4", "$t5", "$t6", "$t7", "$t8", "$x", "$fp", "$s0", +++ "$s1", "$s2", "$s3", "$s4", "$s5", "$s6", "$s7", "$s8", +++}; +++ +++const char * const loongarch_r_lp64_name1[32] = +++{ +++ "", "", "", "", "$v0", "$v1", "", "", +++ "", "", "", "", "", "", "", "", +++ "", "", "", "", "", "", "", "", +++ "", "", "", "", "", "", "", "", +++}; +++ +++const char * const loongarch_f_normal_name[32] = +++{ +++ "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7", +++ "$f8", "$f9", "$f10", "$f11", "$f12", "$f13", "$f14", "$f15", +++ "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23", +++ "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31", +++}; +++ +++const char * const loongarch_f_lp64_name[32] = +++{ +++ "$fa0", "$fa1", "$fa2", "$fa3", "$fa4", "$fa5", "$fa6", "$fa7", +++ "$ft0", "$ft1", "$ft2", "$ft3", "$ft4", "$ft5", "$ft6", "$ft7", +++ "$ft8", "$ft9", "$ft10", "$ft11", "$ft12", "$ft13", "$ft14", "$ft15", +++ "$fs0", "$fs1", "$fs2", "$fs3", "$fs4", "$fs5", "$fs6", "$fs7", +++}; +++ +++const char * const loongarch_f_lp64_name1[32] = +++{ +++ "$fv0", "$fv1", "", "", "", "", "", "", +++ "", "", "", "", "", "", "", "", +++ "", "", "", "", "", "", "", "", +++ "", "", "", "", "", "", "", "", +++}; +++ +++const char * const loongarch_c_normal_name[8] = +++{ +++ "$fcc0", "$fcc1", "$fcc2", "$fcc3", "$fcc4", "$fcc5", "$fcc6", "$fcc7", +++}; +++ +++ +++const char * const loongarch_cr_normal_name[4] = +++{ +++ "$scr0", "$scr1", "$scr2", "$scr3", +++}; +++ +++const char * const loongarch_v_normal_name[32] = +++{ +++ "$vr0", "$vr1", "$vr2", "$vr3", "$vr4", "$vr5", "$vr6", "$vr7", +++ "$vr8", "$vr9", "$vr10", "$vr11", "$vr12", "$vr13", "$vr14", "$vr15", +++ "$vr16", "$vr17", "$vr18", "$vr19", "$vr20", "$vr21", "$vr22", "$vr23", +++ "$vr24", "$vr25", "$vr26", "$vr27", "$vr28", "$vr29", "$vr30", "$vr31", +++}; +++ +++const char * const loongarch_x_normal_name[32] = +++{ +++ "$xr0", "$xr1", "$xr2", "$xr3", "$xr4", "$xr5", "$xr6", "$xr7", +++ "$xr8", "$xr9", "$xr10", "$xr11", "$xr12", "$xr13", "$xr14", "$xr15", +++ "$xr16", "$xr17", "$xr18", "$xr19", "$xr20", "$xr21", "$xr22", "$xr23", +++ "$xr24", "$xr25", "$xr26", "$xr27", "$xr28", "$xr29", "$xr30", "$xr31", +++}; +++ +++#define SOME_INFORMATION 0 +++const int ALWAYS_EXCLUSION = 1; +++static int FIX_FOR_SOME_ARCH = 1; +++ +++static struct loongarch_opcode loongarch_test_opcodes[] = { +++/* match, mask, name, format, macro, include, exclude, pinfo */ +++{ +++0, 0, "a insn always excluded", "r0:5,r5:5,r10:5", +++"insn_1 args_1" +++"insn_2 args_2" +++, 0, &ALWAYS_EXCLUSION, SOME_INFORMATION +++}, +++{ +++0, 0, +++"never disassemble when mask is 0" +++"and we only expand marco when mask is 0 for assemble", +++"r", "macro expand %1" +++, 0, 0, 0 +++}, +++{0, 0, "wrong_insn", "r", +++"throw_error use_fake_insn.for_example.something_goes_wrong_with_%1" +++, 0, 0, 0}, +++ +++{0, 0, "normal_insn", "r", +++"overloading of insn for your arch", &FIX_FOR_SOME_ARCH, 0, 0}, +++{0, 0, "normal_insn", "l", +++"throw_error if_you_dont_want", &FIX_FOR_SOME_ARCH, 0, 0}, +++ +++{0, 0, "normal_insn", "r", "", 0, 0, 0}, +++{0, 0, "normal_insn", "l", "", 0, 0, 0}, +++{0} /* Terminate the list. */ +++}; +++ +++static struct loongarch_opcode loongarch_macro_opcodes[] = { +++/* match, mask, name, format, macro, include, exclude, pinfo */ +++{0, 0, "li.w", "r,sc", "%f", 0, 0, 0}, +++{0, 0, "li.d", "r,sc", "%f", 0, 0, 0}, +++ +++{0, 0, "la", "r,la", "la.global %1,%2", 0, 0, 0}, +++ +++{0, 0, "la.global", "r,la", "la.pcrel %1,%2", &LARCH_opts.la_global_with_pcrel, 0, 0}, +++{0, 0, "la.global", "r,r,la", "la.pcrel %1,%2,%3", &LARCH_opts.la_global_with_pcrel, 0, 0}, +++{0, 0, "la.global", "r,la", "la.abs %1,%2", &LARCH_opts.la_global_with_abs, 0, 0}, +++{0, 0, "la.global", "r,r,la", "la.abs %1,%3", &LARCH_opts.la_global_with_abs, 0, 0}, +++{0, 0, "la.global", "r,l", "la.got %1,%2", 0, 0, 0}, +++{0, 0, "la.global", "r,r,l", "la.got %1,%2,%3", 0, 0, 0}, +++ +++{0, 0, "la.local", "r,la", "la.abs %1,%2", &LARCH_opts.la_local_with_abs, 0, 0}, +++{0, 0, "la.local", "r,r,la", "la.abs %1,%3", &LARCH_opts.la_local_with_abs, 0, 0}, +++{0, 0, "la.local", "r,la", "la.pcrel %1,%2", 0, 0, 0}, +++{0, 0, "la.local", "r,r,la", "la.pcrel %1,%2,%3", 0, 0, 0}, +++ +++{0, 0, "la.abs", "r,la", +++"lu12i.w %1,%%abs(%2)>>12;" +++"ori %1,%1,%%abs(%2)&0xfff;" +++, &LARCH_opts.addrwidth_is_32, 0, 0}, +++{0, 0, "la.abs", "r,la", +++"lu12i.w %1,%%abs(%2)<<32>>44;" +++"ori %1,%1,%%abs(%2)&0xfff;" +++"lu32i.d %1,%%abs(%2)<<12>>44;" +++"lu52i.d %1,%1,%%abs(%2)>>52;" +++, &LARCH_opts.addrwidth_is_64, 0, 0}, +++ +++{0, 0, "la.pcrel", "r,la", +++"pcaddu12i %1,%%pcrel(%2+0x800)<<32>>44;" +++"addi.w %1,%1,%%pcrel(%2+4)-(%%pcrel(%2+4+0x800)>>12<<12);" +++, &LARCH_opts.addrwidth_is_32, 0, 0}, +++ +++{0, 0, "la.pcrel", "r,la", +++"pcaddu12i %1,%%pcrel(%2+0x800)>>12;" +++"addi.d %1,%1,%%pcrel(%2+4)-(%%pcrel(%2+4+0x800)>>12<<12);" +++, &LARCH_opts.addrwidth_is_64, 0, 0}, +++{0, 0, "la.pcrel", "r,r,la", +++"pcaddu12i %1,(%%pcrel(%3)-(%%pcrel(%3+0x80000000)>>32<<32))<<32>>44;" +++"ori %2,$r0,(%%pcrel(%3+4)-(%%pcrel(%3+4+0x80000000)>>32<<32))&0xfff;" +++"lu32i.d %2,%%pcrel(%3+8+0x80000000)<<12>>44;" +++"lu52i.d %2,%2,%%pcrel(%3+12+0x80000000)>>52;" +++"add.d %1,%1,%2;" +++, &LARCH_opts.addrwidth_is_64, 0, 0}, +++ +++{0, 0, "la.got", "r,l", +++"pcaddu12i %1,(%%pcrel(_GLOBAL_OFFSET_TABLE_+0x800)+%%gprel(%2))<<32>>44;" +++"ld.w %1,%1,%%pcrel(_GLOBAL_OFFSET_TABLE_+4)+%%gprel(%2)-((%%pcrel(_GLOBAL_OFFSET_TABLE_+4+0x800)+%%gprel(%2))>>12<<12);" +++, &LARCH_opts.addrwidth_is_32, 0, 0}, +++ +++{0, 0, "la.got", "r,l", +++"pcaddu12i %1,(%%pcrel(_GLOBAL_OFFSET_TABLE_+0x800)+%%gprel(%2))>>12;" +++"ld.d %1,%1,%%pcrel(_GLOBAL_OFFSET_TABLE_+4)+%%gprel(%2)-((%%pcrel(_GLOBAL_OFFSET_TABLE_+4+0x800)+%%gprel(%2))>>12<<12);" +++, &LARCH_opts.addrwidth_is_64, 0, 0}, +++{0, 0, "la.got", "r,r,l", +++"pcaddu12i %1,(%%pcrel(_GLOBAL_OFFSET_TABLE_)+%%gprel(%3)-((%%pcrel(_GLOBAL_OFFSET_TABLE_+0x80000000)+%%gprel(%3))>>32<<32))<<32>>44;" +++"ori %2,$r0,(%%pcrel(_GLOBAL_OFFSET_TABLE_+4)+%%gprel(%3)-((%%pcrel(_GLOBAL_OFFSET_TABLE_+4+0x80000000)+%%gprel(%3))>>32<<32))&0xfff;" +++"lu32i.d %2,(%%pcrel(_GLOBAL_OFFSET_TABLE_+8+0x80000000)+%%gprel(%3))<<12>>44;" +++"lu52i.d %2,%2,(%%pcrel(_GLOBAL_OFFSET_TABLE_+12+0x80000000)+%%gprel(%3))>>52;" +++"ldx.d %1,%1,%2;" +++, &LARCH_opts.addrwidth_is_64, 0, 0}, +++ +++{0, 0, "la.tls.le", "r,la", +++"lu12i.w %1,%%tprel(%2)>>12;" +++"ori %1,%1,%%tprel(%2)&0xfff" +++, &LARCH_opts.addrwidth_is_32, 0, 0}, +++//{0, 0, "la.tls.le", "r,la", +++//"lu12i.w %1,%%tprel(%2)>>12;" +++//"ori %1,%1,%%tprel(%2)&0xfff" +++//, &LARCH_opts.addrwidth_is_64, 0, 0}, +++{0, 0, "la.tls.le", "r,la", +++"lu12i.w %1,%%tprel(%2)<<32>>44;" +++"ori %1,%1,%%tprel(%2)&0xfff;" +++"lu32i.d %1,%%tprel(%2)<<12>>44;" +++"lu52i.d %1,%1,%%tprel(%2)>>52;" +++, &LARCH_opts.addrwidth_is_64, 0, 0}, +++ +++{0, 0, "la.tls.ie", "r,l", +++"pcaddu12i %1,(%%pcrel(_GLOBAL_OFFSET_TABLE_+0x800)+%%tlsgot(%2))<<32>>44;" +++"ld.w %1,%1,%%pcrel(_GLOBAL_OFFSET_TABLE_+4)+%%tlsgot(%2)-((%%pcrel(_GLOBAL_OFFSET_TABLE_+4+0x800)+%%tlsgot(%2))>>12<<12);" +++, &LARCH_opts.addrwidth_is_32, 0, 0}, +++ +++{0, 0, "la.tls.ie", "r,l", +++"pcaddu12i %1,(%%pcrel(_GLOBAL_OFFSET_TABLE_+0x800)+%%tlsgot(%2))>>12;" +++"ld.d %1,%1,%%pcrel(_GLOBAL_OFFSET_TABLE_+4)+%%tlsgot(%2)-((%%pcrel(_GLOBAL_OFFSET_TABLE_+4+0x800)+%%tlsgot(%2))>>12<<12);" +++, &LARCH_opts.addrwidth_is_64, 0, 0}, +++{0, 0, "la.tls.ie", "r,r,l", +++"pcaddu12i %1,(%%pcrel(_GLOBAL_OFFSET_TABLE_)+%%tlsgot(%3)-((%%pcrel(_GLOBAL_OFFSET_TABLE_+0x80000000)+%%tlsgot(%3))>>32<<32))<<32>>44;" +++"ori %2,$r0,(%%pcrel(_GLOBAL_OFFSET_TABLE_+4)+%%tlsgot(%3)-((%%pcrel(_GLOBAL_OFFSET_TABLE_+4+0x80000000)+%%tlsgot(%3))>>32<<32))&0xfff;" +++"lu32i.d %2,(%%pcrel(_GLOBAL_OFFSET_TABLE_+8+0x80000000)+%%tlsgot(%3))<<12>>44;" +++"lu52i.d %2,%2,(%%pcrel(_GLOBAL_OFFSET_TABLE_+12+0x80000000)+%%tlsgot(%3))>>52;" +++"ldx.d %1,%1,%2;" +++, &LARCH_opts.addrwidth_is_64, 0, 0}, +++ +++{0, 0, "la.tls.ld", "r,l", "la.tls.gd %1,%2", 0, 0, 0}, +++{0, 0, "la.tls.ld", "r,r,l", +++"la.tls.gd %1,%2,%3" +++, &LARCH_opts.addrwidth_is_64, 0, 0}, +++ +++ +++{0, 0, "la.tls.gd", "r,l", +++"pcaddu12i %1,(%%pcrel(_GLOBAL_OFFSET_TABLE_+0x800)+%%tlsgd(%2))<<32>>44;" +++"addi.w %1,%1,%%pcrel(_GLOBAL_OFFSET_TABLE_+4)+%%tlsgd(%2)-((%%pcrel(_GLOBAL_OFFSET_TABLE_+4+0x800)+%%tlsgd(%2))>>12<<12);" +++, &LARCH_opts.addrwidth_is_32, 0, 0}, +++ +++{0, 0, "la.tls.gd", "r,l", +++"pcaddu12i %1,(%%pcrel(_GLOBAL_OFFSET_TABLE_+0x800)+%%tlsgd(%2))>>12;" +++"addi.d %1,%1,%%pcrel(_GLOBAL_OFFSET_TABLE_+4)+%%tlsgd(%2)-((%%pcrel(_GLOBAL_OFFSET_TABLE_+4+0x800)+%%tlsgd(%2))>>12<<12);" +++, &LARCH_opts.addrwidth_is_64, 0, 0}, +++{0, 0, "la.tls.gd", "r,r,l", +++"pcaddu12i %1,(%%pcrel(_GLOBAL_OFFSET_TABLE_)+%%tlsgd(%3)-((%%pcrel(_GLOBAL_OFFSET_TABLE_+0x80000000)+%%tlsgd(%3))>>32<<32))<<32>>44;" +++"ori %2,$r0,(%%pcrel(_GLOBAL_OFFSET_TABLE_+4)+%%tlsgd(%3)-((%%pcrel(_GLOBAL_OFFSET_TABLE_+4+0x80000000)+%%tlsgd(%3))>>32<<32))&0xfff;" +++"lu32i.d %2,(%%pcrel(_GLOBAL_OFFSET_TABLE_+8+0x80000000)+%%tlsgd(%3))<<12>>44;" +++"lu52i.d %2,%2,(%%pcrel(_GLOBAL_OFFSET_TABLE_+12+0x80000000)+%%tlsgd(%3))>>52;" +++"add.d %1,%1,%2;" +++, &LARCH_opts.addrwidth_is_64, 0, 0}, +++ +++{0} /* Terminate the list. */ +++}; +++ +++static struct loongarch_opcode loongarch_fix_opcodes[] = +++{ +++ /* match, mask, name, format, macro, include, exclude, pinfo. */ +++ { 0x00001000, 0xfffffc00, "clo.w", "r0:5,r5:5", 0, 0, 0, 0 }, +++ { 0x00001400, 0xfffffc00, "clz.w", "r0:5,r5:5", 0, 0, 0, 0 }, +++ { 0x00001800, 0xfffffc00, "cto.w", "r0:5,r5:5", 0, 0, 0, 0 }, +++ { 0x00001c00, 0xfffffc00, "ctz.w", "r0:5,r5:5", 0, 0, 0, 0 }, +++ { 0x00002000, 0xfffffc00, "clo.d", "r0:5,r5:5", 0, 0, 0, 0 }, +++ { 0x00002400, 0xfffffc00, "clz.d", "r0:5,r5:5", 0, 0, 0, 0 }, +++ { 0x00002800, 0xfffffc00, "cto.d", "r0:5,r5:5", 0, 0, 0, 0 }, +++ { 0x00002c00, 0xfffffc00, "ctz.d", "r0:5,r5:5", 0, 0, 0, 0 }, +++ { 0x00003000, 0xfffffc00, "revb.2h", "r0:5,r5:5", 0, 0, 0, 0 }, +++ { 0x00003400, 0xfffffc00, "revb.4h", "r0:5,r5:5", 0, 0, 0, 0 }, +++ { 0x00003800, 0xfffffc00, "revb.2w", "r0:5,r5:5", 0, 0, 0, 0 }, +++ { 0x00003c00, 0xfffffc00, "revb.d", "r0:5,r5:5", 0, 0, 0, 0 }, +++ { 0x00004000, 0xfffffc00, "revh.2w", "r0:5,r5:5", 0, 0, 0, 0 }, +++ { 0x00004400, 0xfffffc00, "revh.d", "r0:5,r5:5", 0, 0, 0, 0 }, +++ { 0x00004800, 0xfffffc00, "bitrev.4b", "r0:5,r5:5", 0, 0, 0, 0 }, +++ { 0x00004c00, 0xfffffc00, "bitrev.8b", "r0:5,r5:5", 0, 0, 0, 0 }, +++ { 0x00005000, 0xfffffc00, "bitrev.w", "r0:5,r5:5", 0, 0, 0, 0 }, +++ { 0x00005400, 0xfffffc00, "bitrev.d", "r0:5,r5:5", 0, 0, 0, 0 }, +++ { 0x00005800, 0xfffffc00, "ext.w.h", "r0:5,r5:5", 0, 0, 0, 0 }, +++ { 0x00005c00, 0xfffffc00, "ext.w.b", "r0:5,r5:5", 0, 0, 0, 0 }, +++ /* or %1,%2,$r0 */ +++ { 0x00150000, 0xfffffc00, "move", "r0:5,r5:5", 0, 0, 0, 0 }, +++ { 0x00006000, 0xfffffc00, "rdtimel.w", "r0:5,r5:5", 0, 0, 0, 0 }, +++ { 0x00006400, 0xfffffc00, "rdtimeh.w", "r0:5,r5:5", 0, 0, 0, 0 }, +++ { 0x00006800, 0xfffffc00, "rdtime.d", "r0:5,r5:5", 0, 0, 0, 0 }, +++ { 0x00006c00, 0xfffffc00, "cpucfg", "r0:5,r5:5", 0, 0, 0, 0 }, +++ { 0x00010000, 0xffff801f, "asrtle.d", "r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x00018000, 0xffff801f, "asrtgt.d", "r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x00040000, 0xfffe0000, "alsl.w", "r0:5,r5:5,r10:5,u15:2+1", 0, 0, 0, 0 }, +++ { 0x00060000, 0xfffe0000, "alsl.wu", "r0:5,r5:5,r10:5,u15:2+1", 0, 0, 0, 0 }, +++ { 0x00080000, 0xfffe0000, "bytepick.w", "r0:5,r5:5,r10:5,u15:2", 0, 0, 0, 0 }, +++ { 0x000c0000, 0xfffc0000, "bytepick.d", "r0:5,r5:5,r10:5,u15:3", 0, 0, 0, 0 }, +++ { 0x00100000, 0xffff8000, "add.w", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x00108000, 0xffff8000, "add.d", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x00110000, 0xffff8000, "sub.w", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x00118000, 0xffff8000, "sub.d", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x00120000, 0xffff8000, "slt", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x00128000, 0xffff8000, "sltu", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x00130000, 0xffff8000, "maskeqz", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x00138000, 0xffff8000, "masknez", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x00140000, 0xffff8000, "nor", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x00148000, 0xffff8000, "and", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x00150000, 0xffff8000, "or", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x00158000, 0xffff8000, "xor", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x00160000, 0xffff8000, "orn", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x00168000, 0xffff8000, "andn", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x00170000, 0xffff8000, "sll.w", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x00178000, 0xffff8000, "srl.w", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x00180000, 0xffff8000, "sra.w", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x00188000, 0xffff8000, "sll.d", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x00190000, 0xffff8000, "srl.d", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x00198000, 0xffff8000, "sra.d", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x001b0000, 0xffff8000, "rotr.w", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x001b8000, 0xffff8000, "rotr.d", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x001c0000, 0xffff8000, "mul.w", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x001c8000, 0xffff8000, "mulh.w", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x001d0000, 0xffff8000, "mulh.wu", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x001d8000, 0xffff8000, "mul.d", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x001e0000, 0xffff8000, "mulh.d", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x001e8000, 0xffff8000, "mulh.du", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x001f0000, 0xffff8000, "mulw.d.w", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x001f8000, 0xffff8000, "mulw.d.wu", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x00200000, 0xffff8000, "div.w", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x00208000, 0xffff8000, "mod.w", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x00210000, 0xffff8000, "div.wu", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x00218000, 0xffff8000, "mod.wu", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x00220000, 0xffff8000, "div.d", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x00228000, 0xffff8000, "mod.d", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x00230000, 0xffff8000, "div.du", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x00238000, 0xffff8000, "mod.du", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x00240000, 0xffff8000, "crc.w.b.w", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x00248000, 0xffff8000, "crc.w.h.w", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x00250000, 0xffff8000, "crc.w.w.w", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x00258000, 0xffff8000, "crc.w.d.w", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x00260000, 0xffff8000, "crcc.w.b.w", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x00268000, 0xffff8000, "crcc.w.h.w", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x00270000, 0xffff8000, "crcc.w.w.w", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x00278000, 0xffff8000, "crcc.w.d.w", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x002a0000, 0xffff8000, "break", "u0:15", 0, 0, 0, 0 }, +++ { 0x002a8000, 0xffff8000, "dbcl", "u0:15", 0, 0, 0, 0 }, +++ { 0x002b0000, 0xffff8000, "syscall", "u0:15", 0, 0, 0, 0 }, +++ { 0x002c0000, 0xfffe0000, "alsl.d", "r0:5,r5:5,r10:5,u15:2+1", 0, 0, 0, 0 }, +++ { 0x00408000, 0xffff8000, "slli.w", "r0:5,r5:5,u10:5", 0, 0, 0, 0 }, +++ { 0x00410000, 0xffff0000, "slli.d", "r0:5,r5:5,u10:6", 0, 0, 0, 0 }, +++ { 0x00448000, 0xffff8000, "srli.w", "r0:5,r5:5,u10:5", 0, 0, 0, 0 }, +++ { 0x00450000, 0xffff0000, "srli.d", "r0:5,r5:5,u10:6", 0, 0, 0, 0 }, +++ { 0x00488000, 0xffff8000, "srai.w", "r0:5,r5:5,u10:5", 0, 0, 0, 0 }, +++ { 0x00490000, 0xffff0000, "srai.d", "r0:5,r5:5,u10:6", 0, 0, 0, 0 }, +++ { 0x004c8000, 0xffff8000, "rotri.w", "r0:5,r5:5,u10:5", 0, 0, 0, 0 }, +++ { 0x004d0000, 0xffff0000, "rotri.d", "r0:5,r5:5,u10:6", 0, 0, 0, 0 }, +++ { 0x00600000, 0xffe08000, "bstrins.w", "r0:5,r5:5,u16:5,u10:5", 0, 0, 0, 0 }, +++ { 0x00608000, 0xffe08000, "bstrpick.w", "r0:5,r5:5,u16:5,u10:5", 0, 0, 0, 0 }, +++ { 0x00800000, 0xffc00000, "bstrins.d", "r0:5,r5:5,u16:6,u10:6", 0, 0, 0, 0 }, +++ { 0x00c00000, 0xffc00000, "bstrpick.d", "r0:5,r5:5,u16:6,u10:6", 0, 0, 0, 0 }, +++ { 0 } /* Terminate the list. */ +++}; +++ +++static struct loongarch_opcode loongarch_single_float_opcodes[] = +++{ +++ /* match, mask, name, format, macro, include, exclude, pinfo. */ +++ { 0x01008000, 0xffff8000, "fadd.s", "f0:5,f5:5,f10:5", 0, 0, 0, 0 }, +++ { 0x01028000, 0xffff8000, "fsub.s", "f0:5,f5:5,f10:5", 0, 0, 0, 0 }, +++ { 0x01048000, 0xffff8000, "fmul.s", "f0:5,f5:5,f10:5", 0, 0, 0, 0 }, +++ { 0x01068000, 0xffff8000, "fdiv.s", "f0:5,f5:5,f10:5", 0, 0, 0, 0 }, +++ { 0x01088000, 0xffff8000, "fmax.s", "f0:5,f5:5,f10:5", 0, 0, 0, 0 }, +++ { 0x010a8000, 0xffff8000, "fmin.s", "f0:5,f5:5,f10:5", 0, 0, 0, 0 }, +++ { 0x010c8000, 0xffff8000, "fmaxa.s", "f0:5,f5:5,f10:5", 0, 0, 0, 0 }, +++ { 0x010e8000, 0xffff8000, "fmina.s", "f0:5,f5:5,f10:5", 0, 0, 0, 0 }, +++ { 0x01108000, 0xffff8000, "fscaleb.s", "f0:5,f5:5,f10:5", 0, 0, 0, 0 }, +++ { 0x01128000, 0xffff8000, "fcopysign.s", "f0:5,f5:5,f10:5", 0, 0, 0, 0 }, +++ { 0x01140400, 0xfffffc00, "fabs.s", "f0:5,f5:5", 0, 0, 0, 0 }, +++ { 0x01141400, 0xfffffc00, "fneg.s", "f0:5,f5:5", 0, 0, 0, 0 }, +++ { 0x01142400, 0xfffffc00, "flogb.s", "f0:5,f5:5", 0, 0, 0, 0 }, +++ { 0x01143400, 0xfffffc00, "fclass.s", "f0:5,f5:5", 0, 0, 0, 0 }, +++ { 0x01144400, 0xfffffc00, "fsqrt.s", "f0:5,f5:5", 0, 0, 0, 0 }, +++ { 0x01145400, 0xfffffc00, "frecip.s", "f0:5,f5:5", 0, 0, 0, 0 }, +++ { 0x01146400, 0xfffffc00, "frsqrt.s", "f0:5,f5:5", 0, 0, 0, 0 }, +++ { 0x01149400, 0xfffffc00, "fmov.s", "f0:5,f5:5", 0, 0, 0, 0 }, +++ { 0x0114a400, 0xfffffc00, "movgr2fr.w", "f0:5,r5:5", 0, 0, 0, 0 }, +++ { 0x0114ac00, 0xfffffc00, "movgr2frh.w", "f0:5,r5:5", 0, 0, 0, 0 }, +++ { 0x0114b400, 0xfffffc00, "movfr2gr.s", "r0:5,f5:5", 0, 0, 0, 0 }, +++ { 0x0114bc00, 0xfffffc00, "movfrh2gr.s", "r0:5,f5:5", 0, 0, 0, 0 }, +++ { 0x0114c000, 0xfffffc00, "movgr2fcsr", "r0:5,r5:5", 0, 0, 0, 0 }, +++ { 0x0114c800, 0xfffffc00, "movfcsr2gr", "r0:5,r5:5", 0, 0, 0, 0 }, +++ { 0x0114d000, 0xfffffc18, "movfr2cf", "c0:3,f5:5", 0, 0, 0, 0 }, +++ { 0x0114d400, 0xffffff00, "movcf2fr", "f0:5,c5:3", 0, 0, 0, 0 }, +++ { 0x0114d800, 0xfffffc18, "movgr2cf", "c0:3,r5:5", 0, 0, 0, 0 }, +++ { 0x0114dc00, 0xffffff00, "movcf2gr", "r0:5,c5:3", 0, 0, 0, 0 }, +++ { 0x011a0400, 0xfffffc00, "ftintrm.w.s", "f0:5,f5:5", 0, 0, 0, 0 }, +++ { 0x011a2400, 0xfffffc00, "ftintrm.l.s", "f0:5,f5:5", 0, 0, 0, 0 }, +++ { 0x011a4400, 0xfffffc00, "ftintrp.w.s", "f0:5,f5:5", 0, 0, 0, 0 }, +++ { 0x011a6400, 0xfffffc00, "ftintrp.l.s", "f0:5,f5:5", 0, 0, 0, 0 }, +++ { 0x011a8400, 0xfffffc00, "ftintrz.w.s", "f0:5,f5:5", 0, 0, 0, 0 }, +++ { 0x011aa400, 0xfffffc00, "ftintrz.l.s", "f0:5,f5:5", 0, 0, 0, 0 }, +++ { 0x011ac400, 0xfffffc00, "ftintrne.w.s", "f0:5,f5:5", 0, 0, 0, 0 }, +++ { 0x011ae400, 0xfffffc00, "ftintrne.l.s", "f0:5,f5:5", 0, 0, 0, 0 }, +++ { 0x011b0400, 0xfffffc00, "ftint.w.s", "f0:5,f5:5", 0, 0, 0, 0 }, +++ { 0x011b2400, 0xfffffc00, "ftint.l.s", "f0:5,f5:5", 0, 0, 0, 0 }, +++ { 0x011d1000, 0xfffffc00, "ffint.s.w", "f0:5,f5:5", 0, 0, 0, 0 }, +++ { 0x011d1800, 0xfffffc00, "ffint.s.l", "f0:5,f5:5", 0, 0, 0, 0 }, +++ { 0x011e4400, 0xfffffc00, "frint.s", "f0:5,f5:5", 0, 0, 0, 0 }, +++ { 0 } /* Terminate the list. */ +++}; +++ +++static struct loongarch_opcode loongarch_double_float_opcodes[] = +++{ +++ /* match, mask, name, format, macro, include, exclude, pinfo. */ +++ { 0x01010000, 0xffff8000, "fadd.d", "f0:5,f5:5,f10:5", 0, 0, 0, 0 }, +++ { 0x01030000, 0xffff8000, "fsub.d", "f0:5,f5:5,f10:5", 0, 0, 0, 0 }, +++ { 0x01050000, 0xffff8000, "fmul.d", "f0:5,f5:5,f10:5", 0, 0, 0, 0 }, +++ { 0x01070000, 0xffff8000, "fdiv.d", "f0:5,f5:5,f10:5", 0, 0, 0, 0 }, +++ { 0x01090000, 0xffff8000, "fmax.d", "f0:5,f5:5,f10:5", 0, 0, 0, 0 }, +++ { 0x010b0000, 0xffff8000, "fmin.d", "f0:5,f5:5,f10:5", 0, 0, 0, 0 }, +++ { 0x010d0000, 0xffff8000, "fmaxa.d", "f0:5,f5:5,f10:5", 0, 0, 0, 0 }, +++ { 0x010f0000, 0xffff8000, "fmina.d", "f0:5,f5:5,f10:5", 0, 0, 0, 0 }, +++ { 0x01110000, 0xffff8000, "fscaleb.d", "f0:5,f5:5,f10:5", 0, 0, 0, 0 }, +++ { 0x01130000, 0xffff8000, "fcopysign.d", "f0:5,f5:5,f10:5", 0, 0, 0, 0 }, +++ { 0x01140800, 0xfffffc00, "fabs.d", "f0:5,f5:5", 0, 0, 0, 0 }, +++ { 0x01141800, 0xfffffc00, "fneg.d", "f0:5,f5:5", 0, 0, 0, 0 }, +++ { 0x01142800, 0xfffffc00, "flogb.d", "f0:5,f5:5", 0, 0, 0, 0 }, +++ { 0x01143800, 0xfffffc00, "fclass.d", "f0:5,f5:5", 0, 0, 0, 0 }, +++ { 0x01144800, 0xfffffc00, "fsqrt.d", "f0:5,f5:5", 0, 0, 0, 0 }, +++ { 0x01145800, 0xfffffc00, "frecip.d", "f0:5,f5:5", 0, 0, 0, 0 }, +++ { 0x01146800, 0xfffffc00, "frsqrt.d", "f0:5,f5:5", 0, 0, 0, 0 }, +++ { 0x01149800, 0xfffffc00, "fmov.d", "f0:5,f5:5", 0, 0, 0, 0 }, +++ { 0x0114a800, 0xfffffc00, "movgr2fr.d", "f0:5,r5:5", 0, 0, 0, 0 }, +++ { 0x0114b800, 0xfffffc00, "movfr2gr.d", "r0:5,f5:5", 0, 0, 0, 0 }, +++ { 0x01191800, 0xfffffc00, "fcvt.s.d", "f0:5,f5:5", 0, 0, 0, 0 }, +++ { 0x01192400, 0xfffffc00, "fcvt.d.s", "f0:5,f5:5", 0, 0, 0, 0 }, +++ { 0x011a0800, 0xfffffc00, "ftintrm.w.d", "f0:5,f5:5", 0, 0, 0, 0 }, +++ { 0x011a2800, 0xfffffc00, "ftintrm.l.d", "f0:5,f5:5", 0, 0, 0, 0 }, +++ { 0x011a4800, 0xfffffc00, "ftintrp.w.d", "f0:5,f5:5", 0, 0, 0, 0 }, +++ { 0x011a6800, 0xfffffc00, "ftintrp.l.d", "f0:5,f5:5", 0, 0, 0, 0 }, +++ { 0x011a8800, 0xfffffc00, "ftintrz.w.d", "f0:5,f5:5", 0, 0, 0, 0 }, +++ { 0x011aa800, 0xfffffc00, "ftintrz.l.d", "f0:5,f5:5", 0, 0, 0, 0 }, +++ { 0x011ac800, 0xfffffc00, "ftintrne.w.d", "f0:5,f5:5", 0, 0, 0, 0 }, +++ { 0x011ae800, 0xfffffc00, "ftintrne.l.d", "f0:5,f5:5", 0, 0, 0, 0 }, +++ { 0x011b0800, 0xfffffc00, "ftint.w.d", "f0:5,f5:5", 0, 0, 0, 0 }, +++ { 0x011b2800, 0xfffffc00, "ftint.l.d", "f0:5,f5:5", 0, 0, 0, 0 }, +++ { 0x011d2000, 0xfffffc00, "ffint.d.w", "f0:5,f5:5", 0, 0, 0, 0 }, +++ { 0x011d2800, 0xfffffc00, "ffint.d.l", "f0:5,f5:5", 0, 0, 0, 0 }, +++ { 0x011e4800, 0xfffffc00, "frint.d", "f0:5,f5:5", 0, 0, 0, 0 }, +++ { 0 } /* Terminate the list. */ +++}; +++ +++static struct loongarch_opcode loongarch_lmm_opcodes[] = +++{ +++ /* match, mask, name, format, macro, include, exclude, pinfo. */ +++ { 0x02000000, 0xffc00000, "slti", "r0:5,r5:5,s10:12", 0, 0, 0, 0 }, +++ { 0x02400000, 0xffc00000, "sltui", "r0:5,r5:5,s10:12", 0, 0, 0, 0 }, +++ { 0x02800000, 0xffc00000, "addi.w", "r0:5,r5:5,s10:12", 0, 0, 0, 0 }, +++ { 0x02c00000, 0xffc00000, "addi.d", "r0:5,r5:5,s10:12", 0, 0, 0, 0 }, +++ { 0x03000000, 0xffc00000, "lu52i.d", "r0:5,r5:5,s10:12", 0, 0, 0, 0 }, +++ { 0x0, 0x0, "nop", "", "andi $r0,$r0,0", 0, 0, 0 }, +++ { 0x03400000, 0xffc00000, "andi", "r0:5,r5:5,u10:12", 0, 0, 0, 0 }, +++ { 0x03800000, 0xffc00000, "ori", "r0:5,r5:5,u10:12", 0, 0, 0, 0 }, +++ { 0x03c00000, 0xffc00000, "xori", "r0:5,r5:5,u10:12", 0, 0, 0, 0 }, +++ { 0x10000000, 0xfc000000, "addu16i.d", "r0:5,r5:5,s10:16", 0, 0, 0, 0 }, +++ { 0x14000000, 0xfe000000, "lu12i.w", "r0:5,s5:20", 0, 0, 0, 0 }, +++ { 0x16000000, 0xfe000000, "lu32i.d", "r0:5,s5:20", 0, 0, 0, 0 }, +++ { 0x18000000, 0xfe000000, "pcaddi", "r0:5,s5:20", 0, 0, 0, 0 }, +++ { 0x1a000000, 0xfe000000, "pcalau12i", "r0:5,s5:20", 0, 0, 0, 0 }, +++ { 0x1c000000, 0xfe000000, "pcaddu12i", "r0:5,s5:20", 0, 0, 0, 0 }, +++ { 0x1e000000, 0xfe000000, "pcaddu18i", "r0:5,s5:20", 0, 0, 0, 0 }, +++ { 0 } /* Terminate the list. */ +++}; +++ +++static struct loongarch_opcode loongarch_privilege_opcodes[] = +++{ +++ /* match, mask, name, format, macro, include, exclude, pinfo. */ +++ { 0x04000000, 0xff0003e0, "csrrd", "r0:5,u10:14", 0, 0, 0, 0 }, +++ { 0x04000020, 0xff0003e0, "csrwr", "r0:5,u10:14", 0, 0, 0, 0 }, +++ { 0x04000000, 0xff000000, "csrxchg", "r0:5,r5:5,u10:14", 0, 0, 0, 0 }, +++ { 0x06000000, 0xffc00000, "cacop", "u0:5,r5:5,s10:12", 0, 0, 0, 0 }, +++ { 0x06400000, 0xfffc0000, "lddir", "r0:5,r5:5,u10:8", 0, 0, 0, 0 }, +++ { 0x06440000, 0xfffc001f, "ldpte", "r5:5,u10:8", 0, 0, 0, 0 }, +++ { 0x06480000, 0xfffffc00, "iocsrrd.b", "r0:5,r5:5", 0, 0, 0, 0 }, +++ { 0x06480400, 0xfffffc00, "iocsrrd.h", "r0:5,r5:5", 0, 0, 0, 0 }, +++ { 0x06480800, 0xfffffc00, "iocsrrd.w", "r0:5,r5:5", 0, 0, 0, 0 }, +++ { 0x06480c00, 0xfffffc00, "iocsrrd.d", "r0:5,r5:5", 0, 0, 0, 0 }, +++ { 0x06481000, 0xfffffc00, "iocsrwr.b", "r0:5,r5:5", 0, 0, 0, 0 }, +++ { 0x06481400, 0xfffffc00, "iocsrwr.h", "r0:5,r5:5", 0, 0, 0, 0 }, +++ { 0x06481800, 0xfffffc00, "iocsrwr.w", "r0:5,r5:5", 0, 0, 0, 0 }, +++ { 0x06481c00, 0xfffffc00, "iocsrwr.d", "r0:5,r5:5", 0, 0, 0, 0 }, +++ { 0x06482000, 0xffffffff, "tlbclr", "", 0, 0, 0, 0 }, +++ { 0x06482400, 0xffffffff, "tlbflush", "", 0, 0, 0, 0 }, +++ { 0x06482800, 0xffffffff, "tlbsrch", "", 0, 0, 0, 0 }, +++ { 0x06482c00, 0xffffffff, "tlbrd", "", 0, 0, 0, 0 }, +++ { 0x06483000, 0xffffffff, "tlbwr", "", 0, 0, 0, 0 }, +++ { 0x06483400, 0xffffffff, "tlbfill", "", 0, 0, 0, 0 }, +++ { 0x06483800, 0xffffffff, "ertn", "", 0, 0, 0, 0 }, +++ { 0x06488000, 0xffff8000, "idle", "u0:15", 0, 0, 0, 0 }, +++ { 0x06498000, 0xffff8000, "invtlb", "u0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0 } /* Terminate the list. */ +++}; +++ +++static struct loongarch_opcode loongarch_4opt_single_float_opcodes[] = +++{ +++ /* match, mask, name, format, macro, include, exclude, pinfo. */ +++ { 0x08100000, 0xfff00000, "fmadd.s", "f0:5,f5:5,f10:5,f15:5", 0, 0, 0, 0 }, +++ { 0x08500000, 0xfff00000, "fmsub.s", "f0:5,f5:5,f10:5,f15:5", 0, 0, 0, 0 }, +++ { 0x08900000, 0xfff00000, "fnmadd.s", "f0:5,f5:5,f10:5,f15:5", 0, 0, 0, 0 }, +++ { 0x08d00000, 0xfff00000, "fnmsub.s", "f0:5,f5:5,f10:5,f15:5", 0, 0, 0, 0 }, +++ { 0x0c100000, 0xffff8018, "fcmp.caf.s", "c0:3,f5:5,f10:5", 0, 0, 0, 0 }, +++ { 0x0c108000, 0xffff8018, "fcmp.saf.s", "c0:3,f5:5,f10:5", 0, 0, 0, 0 }, +++ { 0x0c110000, 0xffff8018, "fcmp.clt.s", "c0:3,f5:5,f10:5", 0, 0, 0, 0 }, +++ { 0x0c118000, 0xffff8018, "fcmp.slt.s", "c0:3,f5:5,f10:5", 0, 0, 0, 0 }, +++ { 0x0c118000, 0xffff8018, "fcmp.sgt.s", "c0:3,f10:5,f5:5", 0, 0, 0, 0 }, +++ { 0x0c120000, 0xffff8018, "fcmp.ceq.s", "c0:3,f5:5,f10:5", 0, 0, 0, 0 }, +++ { 0x0c128000, 0xffff8018, "fcmp.seq.s", "c0:3,f5:5,f10:5", 0, 0, 0, 0 }, +++ { 0x0c130000, 0xffff8018, "fcmp.cle.s", "c0:3,f5:5,f10:5", 0, 0, 0, 0 }, +++ { 0x0c138000, 0xffff8018, "fcmp.sle.s", "c0:3,f5:5,f10:5", 0, 0, 0, 0 }, +++ { 0x0c138000, 0xffff8018, "fcmp.sge.s", "c0:3,f10:5,f5:5", 0, 0, 0, 0 }, +++ { 0x0c140000, 0xffff8018, "fcmp.cun.s", "c0:3,f5:5,f10:5", 0, 0, 0, 0 }, +++ { 0x0c148000, 0xffff8018, "fcmp.sun.s", "c0:3,f5:5,f10:5", 0, 0, 0, 0 }, +++ { 0x0c150000, 0xffff8018, "fcmp.cult.s", "c0:3,f5:5,f10:5", 0, 0, 0, 0 }, +++ { 0x0c150000, 0xffff8018, "fcmp.cugt.s", "c0:3,f10:5,f5:5", 0, 0, 0, 0 }, +++ { 0x0c158000, 0xffff8018, "fcmp.sult.s", "c0:3,f5:5,f10:5", 0, 0, 0, 0 }, +++ { 0x0c160000, 0xffff8018, "fcmp.cueq.s", "c0:3,f5:5,f10:5", 0, 0, 0, 0 }, +++ { 0x0c168000, 0xffff8018, "fcmp.sueq.s", "c0:3,f5:5,f10:5", 0, 0, 0, 0 }, +++ { 0x0c170000, 0xffff8018, "fcmp.cule.s", "c0:3,f5:5,f10:5", 0, 0, 0, 0 }, +++ { 0x0c170000, 0xffff8018, "fcmp.cuge.s", "c0:3,f10:5,f5:5", 0, 0, 0, 0 }, +++ { 0x0c178000, 0xffff8018, "fcmp.sule.s", "c0:3,f5:5,f10:5", 0, 0, 0, 0 }, +++ { 0x0c180000, 0xffff8018, "fcmp.cne.s", "c0:3,f5:5,f10:5", 0, 0, 0, 0 }, +++ { 0x0c188000, 0xffff8018, "fcmp.sne.s", "c0:3,f5:5,f10:5", 0, 0, 0, 0 }, +++ { 0x0c1a0000, 0xffff8018, "fcmp.cor.s", "c0:3,f5:5,f10:5", 0, 0, 0, 0 }, +++ { 0x0c1a8000, 0xffff8018, "fcmp.sor.s", "c0:3,f5:5,f10:5", 0, 0, 0, 0 }, +++ { 0x0c1c0000, 0xffff8018, "fcmp.cune.s", "c0:3,f5:5,f10:5", 0, 0, 0, 0 }, +++ { 0x0c1c8000, 0xffff8018, "fcmp.sune.s", "c0:3,f5:5,f10:5", 0, 0, 0, 0 }, +++ { 0x0d000000, 0xfffc0000, "fsel", "f0:5,f5:5,f10:5,c15:3", 0, 0, 0, 0 }, +++ { 0 } /* Terminate the list. */ +++}; +++static struct loongarch_opcode loongarch_4opt_double_float_opcodes[] = +++{ +++ /* match, mask, name, format, macro, include, exclude, pinfo. */ +++ { 0x08200000, 0xfff00000, "fmadd.d", "f0:5,f5:5,f10:5,f15:5", 0, 0, 0, 0 }, +++ { 0x08600000, 0xfff00000, "fmsub.d", "f0:5,f5:5,f10:5,f15:5", 0, 0, 0, 0 }, +++ { 0x08a00000, 0xfff00000, "fnmadd.d", "f0:5,f5:5,f10:5,f15:5", 0, 0, 0, 0 }, +++ { 0x08e00000, 0xfff00000, "fnmsub.d", "f0:5,f5:5,f10:5,f15:5", 0, 0, 0, 0 }, +++ { 0x0c200000, 0xffff8018, "fcmp.caf.d", "c0:3,f5:5,f10:5", 0, 0, 0, 0 }, +++ { 0x0c208000, 0xffff8018, "fcmp.saf.d", "c0:3,f5:5,f10:5", 0, 0, 0, 0 }, +++ { 0x0c210000, 0xffff8018, "fcmp.clt.d", "c0:3,f5:5,f10:5", 0, 0, 0, 0 }, +++ { 0x0c218000, 0xffff8018, "fcmp.slt.d", "c0:3,f5:5,f10:5", 0, 0, 0, 0 }, +++ { 0x0c218000, 0xffff8018, "fcmp.sgt.d", "c0:3,f10:5,f5:5", 0, 0, 0, 0 }, +++ { 0x0c220000, 0xffff8018, "fcmp.ceq.d", "c0:3,f5:5,f10:5", 0, 0, 0, 0 }, +++ { 0x0c228000, 0xffff8018, "fcmp.seq.d", "c0:3,f5:5,f10:5", 0, 0, 0, 0 }, +++ { 0x0c230000, 0xffff8018, "fcmp.cle.d", "c0:3,f5:5,f10:5", 0, 0, 0, 0 }, +++ { 0x0c238000, 0xffff8018, "fcmp.sle.d", "c0:3,f5:5,f10:5", 0, 0, 0, 0 }, +++ { 0x0c238000, 0xffff8018, "fcmp.sge.d", "c0:3,f10:5,f5:5", 0, 0, 0, 0 }, +++ { 0x0c240000, 0xffff8018, "fcmp.cun.d", "c0:3,f5:5,f10:5", 0, 0, 0, 0 }, +++ { 0x0c248000, 0xffff8018, "fcmp.sun.d", "c0:3,f5:5,f10:5", 0, 0, 0, 0 }, +++ { 0x0c250000, 0xffff8018, "fcmp.cult.d", "c0:3,f5:5,f10:5", 0, 0, 0, 0 }, +++ { 0x0c250000, 0xffff8018, "fcmp.cugt.d", "c0:3,f10:5,f5:5", 0, 0, 0, 0 }, +++ { 0x0c258000, 0xffff8018, "fcmp.sult.d", "c0:3,f5:5,f10:5", 0, 0, 0, 0 }, +++ { 0x0c260000, 0xffff8018, "fcmp.cueq.d", "c0:3,f5:5,f10:5", 0, 0, 0, 0 }, +++ { 0x0c268000, 0xffff8018, "fcmp.sueq.d", "c0:3,f5:5,f10:5", 0, 0, 0, 0 }, +++ { 0x0c270000, 0xffff8018, "fcmp.cule.d", "c0:3,f5:5,f10:5", 0, 0, 0, 0 }, +++ { 0x0c270000, 0xffff8018, "fcmp.cuge.d", "c0:3,f10:5,f5:5", 0, 0, 0, 0 }, +++ { 0x0c278000, 0xffff8018, "fcmp.sule.d", "c0:3,f5:5,f10:5", 0, 0, 0, 0 }, +++ { 0x0c280000, 0xffff8018, "fcmp.cne.d", "c0:3,f5:5,f10:5", 0, 0, 0, 0 }, +++ { 0x0c288000, 0xffff8018, "fcmp.sne.d", "c0:3,f5:5,f10:5", 0, 0, 0, 0 }, +++ { 0x0c2a0000, 0xffff8018, "fcmp.cor.d", "c0:3,f5:5,f10:5", 0, 0, 0, 0 }, +++ { 0x0c2a8000, 0xffff8018, "fcmp.sor.d", "c0:3,f5:5,f10:5", 0, 0, 0, 0 }, +++ { 0x0c2c0000, 0xffff8018, "fcmp.cune.d", "c0:3,f5:5,f10:5", 0, 0, 0, 0 }, +++ { 0x0c2c8000, 0xffff8018, "fcmp.sune.d", "c0:3,f5:5,f10:5", 0, 0, 0, 0 }, +++ { 0 } /* Terminate the list. */ +++}; +++ +++static struct loongarch_opcode loongarch_load_store_opcodes[] = +++{ +++ /* match, mask, name, format, macro, include, exclude, pinfo. */ +++ { 0x20000000, 0xff000000, "ll.w", "r0:5,r5:5,s10:14<<2", 0, 0, 0, 0 }, +++ { 0x21000000, 0xff000000, "sc.w", "r0:5,r5:5,s10:14<<2", 0, 0, 0, 0 }, +++ { 0x22000000, 0xff000000, "ll.d", "r0:5,r5:5,s10:14<<2", 0, 0, 0, 0 }, +++ { 0x23000000, 0xff000000, "sc.d", "r0:5,r5:5,s10:14<<2", 0, 0, 0, 0 }, +++ { 0x24000000, 0xff000000, "ldptr.w", "r0:5,r5:5,s10:14<<2", 0, 0, 0, 0 }, +++ { 0x25000000, 0xff000000, "stptr.w", "r0:5,r5:5,s10:14<<2", 0, 0, 0, 0 }, +++ { 0x26000000, 0xff000000, "ldptr.d", "r0:5,r5:5,s10:14<<2", 0, 0, 0, 0 }, +++ { 0x27000000, 0xff000000, "stptr.d", "r0:5,r5:5,s10:14<<2", 0, 0, 0, 0 }, +++ { 0x28000000, 0xffc00000, "ld.b", "r0:5,r5:5,s10:12", 0, 0, 0, 0 }, +++ { 0x28400000, 0xffc00000, "ld.h", "r0:5,r5:5,s10:12", 0, 0, 0, 0 }, +++ { 0x28800000, 0xffc00000, "ld.w", "r0:5,r5:5,s10:12", 0, 0, 0, 0 }, +++ { 0x28c00000, 0xffc00000, "ld.d", "r0:5,r5:5,s10:12", 0, 0, 0, 0 }, +++ { 0x29000000, 0xffc00000, "st.b", "r0:5,r5:5,s10:12", 0, 0, 0, 0 }, +++ { 0x29400000, 0xffc00000, "st.h", "r0:5,r5:5,s10:12", 0, 0, 0, 0 }, +++ { 0x29800000, 0xffc00000, "st.w", "r0:5,r5:5,s10:12", 0, 0, 0, 0 }, +++ { 0x29c00000, 0xffc00000, "st.d", "r0:5,r5:5,s10:12", 0, 0, 0, 0 }, +++ { 0x2a000000, 0xffc00000, "ld.bu", "r0:5,r5:5,s10:12", 0, 0, 0, 0 }, +++ { 0x2a400000, 0xffc00000, "ld.hu", "r0:5,r5:5,s10:12", 0, 0, 0, 0 }, +++ { 0x2a800000, 0xffc00000, "ld.wu", "r0:5,r5:5,s10:12", 0, 0, 0, 0 }, +++ { 0x2ac00000, 0xffc00000, "preld", "u0:5,r5:5,s10:12", 0, 0, 0, 0 }, +++ { 0x38000000, 0xffff8000, "ldx.b", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x38040000, 0xffff8000, "ldx.h", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x38080000, 0xffff8000, "ldx.w", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x380c0000, 0xffff8000, "ldx.d", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x38100000, 0xffff8000, "stx.b", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x38140000, 0xffff8000, "stx.h", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x38180000, 0xffff8000, "stx.w", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x381c0000, 0xffff8000, "stx.d", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x38200000, 0xffff8000, "ldx.bu", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x38240000, 0xffff8000, "ldx.hu", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x38280000, 0xffff8000, "ldx.wu", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x382c0000, 0xffff8000, "preldx", "u0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x0, 0x0, "amswap.w", "r,r,r,u0:0", "amswap.w %1,%2,%3", 0, 0, 0 }, +++ { 0x38600000, 0xffff8000, "amswap.w", "r0:5,r10:5,r5:5", 0, 0, 0, 0 }, +++ { 0x0, 0x0, "amswap.d", "r,r,r,u0:0", "amswap.d %1,%2,%3", 0, 0, 0 }, +++ { 0x38608000, 0xffff8000, "amswap.d", "r0:5,r10:5,r5:5", 0, 0, 0, 0 }, +++ { 0x0, 0x0, "amadd.w", "r,r,r,u0:0", "amadd.w %1,%2,%3", 0, 0, 0 }, +++ { 0x38610000, 0xffff8000, "amadd.w", "r0:5,r10:5,r5:5", 0, 0, 0, 0 }, +++ { 0x0, 0x0, "amadd.d", "r,r,r,u0:0", "amadd.d %1,%2,%3", 0, 0, 0 }, +++ { 0x38618000, 0xffff8000, "amadd.d", "r0:5,r10:5,r5:5", 0, 0, 0, 0 }, +++ { 0x0, 0x0, "amand.w", "r,r,r,u0:0", "amand.w %1,%2,%3", 0, 0, 0 }, +++ { 0x38620000, 0xffff8000, "amand.w", "r0:5,r10:5,r5:5", 0, 0, 0, 0 }, +++ { 0x0, 0x0, "amand.d", "r,r,r,u0:0", "amand.d %1,%2,%3", 0, 0, 0 }, +++ { 0x38628000, 0xffff8000, "amand.d", "r0:5,r10:5,r5:5", 0, 0, 0, 0 }, +++ { 0x0, 0x0, "amor.w", "r,r,r,u0:0", "amor.w %1,%2,%3", 0, 0, 0 }, +++ { 0x38630000, 0xffff8000, "amor.w", "r0:5,r10:5,r5:5", 0, 0, 0, 0 }, +++ { 0x0, 0x0, "amor.d", "r,r,r,u0:0", "amor.d %1,%2,%3", 0, 0, 0 }, +++ { 0x38638000, 0xffff8000, "amor.d", "r0:5,r10:5,r5:5", 0, 0, 0, 0 }, +++ { 0x0, 0x0, "amxor.w", "r,r,r,u0:0", "amxor.w %1,%2,%3", 0, 0, 0 }, +++ { 0x38640000, 0xffff8000, "amxor.w", "r0:5,r10:5,r5:5", 0, 0, 0, 0 }, +++ { 0x0, 0x0, "amxor.d", "r,r,r,u0:0", "amxor.d %1,%2,%3", 0, 0, 0 }, +++ { 0x38648000, 0xffff8000, "amxor.d", "r0:5,r10:5,r5:5", 0, 0, 0, 0 }, +++ { 0x0, 0x0, "ammax.w", "r,r,r,u0:0", "ammax.w %1,%2,%3", 0, 0, 0 }, +++ { 0x38650000, 0xffff8000, "ammax.w", "r0:5,r10:5,r5:5", 0, 0, 0, 0 }, +++ { 0x0, 0x0, "ammax.d", "r,r,r,u0:0", "ammax.d %1,%2,%3", 0, 0, 0 }, +++ { 0x38658000, 0xffff8000, "ammax.d", "r0:5,r10:5,r5:5", 0, 0, 0, 0 }, +++ { 0x0, 0x0, "ammin.w", "r,r,r,u0:0", "ammin.w %1,%2,%3", 0, 0, 0 }, +++ { 0x38660000, 0xffff8000, "ammin.w", "r0:5,r10:5,r5:5", 0, 0, 0, 0 }, +++ { 0x0, 0x0, "ammin.d", "r,r,r,u0:0", "ammin.d %1,%2,%3", 0, 0, 0 }, +++ { 0x38668000, 0xffff8000, "ammin.d", "r0:5,r10:5,r5:5", 0, 0, 0, 0 }, +++ { 0x0, 0x0, "ammax.wu", "r,r,r,u0:0", "ammax.wu %1,%2,%3", 0, 0, 0 }, +++ { 0x38670000, 0xffff8000, "ammax.wu", "r0:5,r10:5,r5:5", 0, 0, 0, 0 }, +++ { 0x0, 0x0, "ammax.du", "r,r,r,u0:0", "ammax.du %1,%2,%3", 0, 0, 0 }, +++ { 0x38678000, 0xffff8000, "ammax.du", "r0:5,r10:5,r5:5", 0, 0, 0, 0 }, +++ { 0x0, 0x0, "ammin.wu", "r,r,r,u0:0", "ammin.wu %1,%2,%3", 0, 0, 0 }, +++ { 0x38680000, 0xffff8000, "ammin.wu", "r0:5,r10:5,r5:5", 0, 0, 0, 0 }, +++ { 0x0, 0x0, "ammin.du", "r,r,r,u0:0", "ammin.du %1,%2,%3", 0, 0, 0 }, +++ { 0x38688000, 0xffff8000, "ammin.du", "r0:5,r10:5,r5:5", 0, 0, 0, 0 }, +++ { 0x0, 0x0, "amswap_db.w", "r,r,r,u0:0", "amswap_db.w %1,%2,%3", 0, 0, 0 }, +++ { 0x38690000, 0xffff8000, "amswap_db.w", "r0:5,r10:5,r5:5", 0, 0, 0, 0 }, +++ { 0x0, 0x0, "amswap_db.d", "r,r,r,u0:0", "amswap_db.d %1,%2,%3", 0, 0, 0 }, +++ { 0x38698000, 0xffff8000, "amswap_db.d", "r0:5,r10:5,r5:5", 0, 0, 0, 0 }, +++ { 0x0, 0x0, "amadd_db.w", "r,r,r,u0:0", "amadd_db.w %1,%2,%3", 0, 0, 0 }, +++ { 0x386a0000, 0xffff8000, "amadd_db.w", "r0:5,r10:5,r5:5", 0, 0, 0, 0 }, +++ { 0x0, 0x0, "amadd_db.d", "r,r,r,u0:0", "amadd_db.d %1,%2,%3", 0, 0, 0 }, +++ { 0x386a8000, 0xffff8000, "amadd_db.d", "r0:5,r10:5,r5:5", 0, 0, 0, 0 }, +++ { 0x0, 0x0, "amand_db.w", "r,r,r,u0:0", "amand_db.w %1,%2,%3", 0, 0, 0 }, +++ { 0x386b0000, 0xffff8000, "amand_db.w", "r0:5,r10:5,r5:5", 0, 0, 0, 0 }, +++ { 0x0, 0x0, "amand_db.d", "r,r,r,u0:0", "amand_db.d %1,%2,%3", 0, 0, 0 }, +++ { 0x386b8000, 0xffff8000, "amand_db.d", "r0:5,r10:5,r5:5", 0, 0, 0, 0 }, +++ { 0x0, 0x0, "amor_db.w", "r,r,r,u0:0", "amor_db.w %1,%2,%3", 0, 0, 0 }, +++ { 0x386c0000, 0xffff8000, "amor_db.w", "r0:5,r10:5,r5:5", 0, 0, 0, 0 }, +++ { 0x0, 0x0, "amor_db.d", "r,r,r,u0:0", "amor_db.d %1,%2,%3", 0, 0, 0 }, +++ { 0x386c8000, 0xffff8000, "amor_db.d", "r0:5,r10:5,r5:5", 0, 0, 0, 0 }, +++ { 0x0, 0x0, "amxor_db.w", "r,r,r,u0:0", "amxor_db.w %1,%2,%3", 0, 0, 0 }, +++ { 0x386d0000, 0xffff8000, "amxor_db.w", "r0:5,r10:5,r5:5", 0, 0, 0, 0 }, +++ { 0x0, 0x0, "amxor_db.d", "r,r,r,u0:0", "amxor_db.d %1,%2,%3", 0, 0, 0 }, +++ { 0x386d8000, 0xffff8000, "amxor_db.d", "r0:5,r10:5,r5:5", 0, 0, 0, 0 }, +++ { 0x0, 0x0, "ammax_db.w", "r,r,r,u0:0", "ammax_db.w %1,%2,%3", 0, 0, 0 }, +++ { 0x386e0000, 0xffff8000, "ammax_db.w", "r0:5,r10:5,r5:5", 0, 0, 0, 0 }, +++ { 0x0, 0x0, "ammax_db.d", "r,r,r,u0:0", "ammax_db.d %1,%2,%3", 0, 0, 0 }, +++ { 0x386e8000, 0xffff8000, "ammax_db.d", "r0:5,r10:5,r5:5", 0, 0, 0, 0 }, +++ { 0x0, 0x0, "ammin_db.w", "r,r,r,u0:0", "ammin_db.w %1,%2,%3", 0, 0, 0 }, +++ { 0x386f0000, 0xffff8000, "ammin_db.w", "r0:5,r10:5,r5:5", 0, 0, 0, 0 }, +++ { 0x0, 0x0, "ammin_db.d", "r,r,r,u0:0", "ammin_db.d %1,%2,%3", 0, 0, 0 }, +++ { 0x386f8000, 0xffff8000, "ammin_db.d", "r0:5,r10:5,r5:5", 0, 0, 0, 0 }, +++ { 0x0, 0x0, "ammax_db.wu", "r,r,r,u0:0", "ammax_db.wu %1,%2,%3", 0, 0, 0 }, +++ { 0x38700000, 0xffff8000, "ammax_db.wu", "r0:5,r10:5,r5:5", 0, 0, 0, 0 }, +++ { 0x0, 0x0, "ammax_db.du", "r,r,r,u0:0", "ammax_db.du %1,%2,%3", 0, 0, 0 }, +++ { 0x38708000, 0xffff8000, "ammax_db.du", "r0:5,r10:5,r5:5", 0, 0, 0, 0 }, +++ { 0x0, 0x0, "ammin_db.wu", "r,r,r,u0:0", "ammin_db.wu %1,%2,%3", 0, 0, 0 }, +++ { 0x38710000, 0xffff8000, "ammin_db.wu", "r0:5,r10:5,r5:5", 0, 0, 0, 0 }, +++ { 0x0, 0x0, "ammin_db.du", "r,r,r,u0:0", "ammin_db.du %1,%2,%3", 0, 0, 0 }, +++ { 0x38718000, 0xffff8000, "ammin_db.du", "r0:5,r10:5,r5:5", 0, 0, 0, 0 }, +++ { 0x38720000, 0xffff8000, "dbar", "u0:15", 0, 0, 0, 0 }, +++ { 0x38728000, 0xffff8000, "ibar", "u0:15", 0, 0, 0, 0 }, +++ { 0x38780000, 0xffff8000, "ldgt.b", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x38788000, 0xffff8000, "ldgt.h", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x38790000, 0xffff8000, "ldgt.w", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x38798000, 0xffff8000, "ldgt.d", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x387a0000, 0xffff8000, "ldle.b", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x387a8000, 0xffff8000, "ldle.h", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x387b0000, 0xffff8000, "ldle.w", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x387b8000, 0xffff8000, "ldle.d", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x387c0000, 0xffff8000, "stgt.b", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x387c8000, 0xffff8000, "stgt.h", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x387d0000, 0xffff8000, "stgt.w", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x387d8000, 0xffff8000, "stgt.d", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x387e0000, 0xffff8000, "stle.b", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x387e8000, 0xffff8000, "stle.h", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x387f0000, 0xffff8000, "stle.w", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x387f8000, 0xffff8000, "stle.d", "r0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0 } /* Terminate the list. */ +++}; +++ +++static struct loongarch_opcode loongarch_single_float_load_store_opcodes[] = +++{ +++ /* match, mask, name, format, macro, include, exclude, pinfo. */ +++ { 0x2b000000, 0xffc00000, "fld.s", "f0:5,r5:5,s10:12", 0, 0, 0, 0 }, +++ { 0x2b400000, 0xffc00000, "fst.s", "f0:5,r5:5,s10:12", 0, 0, 0, 0 }, +++ { 0x38300000, 0xffff8000, "fldx.s", "f0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x38380000, 0xffff8000, "fstx.s", "f0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x38740000, 0xffff8000, "fldgt.s", "f0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x38750000, 0xffff8000, "fldle.s", "f0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x38760000, 0xffff8000, "fstgt.s", "f0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x38770000, 0xffff8000, "fstle.s", "f0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0 } /* Terminate the list. */ +++}; +++ +++static struct loongarch_opcode loongarch_double_float_load_store_opcodes[] = +++{ +++ /* match, mask, name, format, macro, include, exclude, pinfo. */ +++ { 0x2b800000, 0xffc00000, "fld.d", "f0:5,r5:5,s10:12", 0, 0, 0, 0 }, +++ { 0x2bc00000, 0xffc00000, "fst.d", "f0:5,r5:5,s10:12", 0, 0, 0, 0 }, +++ { 0x38340000, 0xffff8000, "fldx.d", "f0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x383c0000, 0xffff8000, "fstx.d", "f0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x38748000, 0xffff8000, "fldgt.d", "f0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x38758000, 0xffff8000, "fldle.d", "f0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x38768000, 0xffff8000, "fstgt.d", "f0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0x38778000, 0xffff8000, "fstle.d", "f0:5,r5:5,r10:5", 0, 0, 0, 0 }, +++ { 0 } /* Terminate the list. */ +++}; +++ +++static struct loongarch_opcode loongarch_float_jmp_opcodes[] = +++{ +++ { 0x0, 0x0, "bceqz", "c,la", "bceqz %1,%%pcrel(%2)", 0, 0, 0 }, +++ { 0x48000000, 0xfc000300, "bceqz", "c5:3,sb0:5|10:16<<2", 0, 0, 0, 0 }, +++ { 0x0, 0x0, "bcnez", "c,la", "bcnez %1,%%pcrel(%2)", 0, 0, 0 }, +++ { 0x48000100, 0xfc000300, "bcnez", "c5:3,sb0:5|10:16<<2", 0, 0, 0, 0 }, +++ { 0 } /* Terminate the list. */ +++}; +++ +++static struct loongarch_opcode loongarch_jmp_opcodes[] = +++{ +++ /* match, mask, name, format, macro, include, exclude, pinfo. */ +++ { 0x0, 0x0, "bltz", "r,la", "bltz %1,%%pcrel(%2)", 0, 0, 0 }, +++ { 0x60000000, 0xfc00001f, "bltz", "r5:5,sb10:16<<2", 0, 0, 0, 0 }, +++ { 0x0, 0x0, "bgtz", "r,la", "bgtz %1,%%pcrel(%2)", 0, 0, 0 }, +++ { 0x60000000, 0xfc0003e0, "bgtz", "r0:5,sb10:16<<2", 0, 0, 0, 0 }, +++ { 0x0, 0x0, "bgez", "r,la", "bgez %1,%%pcrel(%2)", 0, 0, 0 }, +++ { 0x64000000, 0xfc00001f, "bgez", "r5:5,sb10:16<<2", 0, 0, 0, 0 }, +++ { 0x0, 0x0, "blez", "r,la", "blez %1,%%pcrel(%2)", 0, 0, 0 }, +++ { 0x64000000, 0xfc0003e0, "blez", "r0:5,sb10:16<<2", 0, 0, 0, 0 }, +++ { 0x0, 0x0, "beqz", "r,la", "beqz %1,%%pcrel(%2)", 0, 0, 0 }, +++ { 0x40000000, 0xfc000000, "beqz", "r5:5,sb0:5|10:16<<2", 0, 0, 0, 0 }, +++ { 0x0, 0x0, "bnez", "r,la", "bnez %1,%%pcrel(%2)", 0, 0, 0 }, +++ { 0x44000000, 0xfc000000, "bnez", "r5:5,sb0:5|10:16<<2", 0, 0, 0, 0 }, +++ { 0x0, 0x0, "jr", "r", "jirl $r0,%1,0", 0, 0, 0 }, +++ { 0x50000000, 0xfc000000, "b", "sb0:10|10:16<<2", 0, 0, 0, 0 }, +++ { 0x0, 0x0, "b", "la", "b %%pcrel(%1)", 0, 0, 0 }, +++ { 0x4c000000, 0xfc000000, "jirl", "r0:5,r5:5,s10:16<<2", 0, 0, 0, 0 }, +++ { 0x0, 0x0, "bl", "la", "bl %%pcrel(%1)", 0, 0, 0 }, +++ { 0x54000000, 0xfc000000, "bl", "sb0:10|10:16<<2", 0, 0, 0, 0 }, +++ { 0x0, 0x0, "beq", "r,r,la", "beq %1,%2,%%pcrel(%3)", 0, 0, 0 }, +++ { 0x58000000, 0xfc000000, "beq", "r5:5,r0:5,sb10:16<<2", 0, 0, 0, 0 }, +++ { 0x0, 0x0, "bne", "r,r,la", "bne %1,%2,%%pcrel(%3)", 0, 0, 0 }, +++ { 0x5c000000, 0xfc000000, "bne", "r5:5,r0:5,sb10:16<<2", 0, 0, 0, 0 }, +++ { 0x0, 0x0, "blt", "r,r,la", "blt %1,%2,%%pcrel(%3)", 0, 0, 0 }, +++ { 0x60000000, 0xfc000000, "blt", "r5:5,r0:5,sb10:16<<2", 0, 0, 0, 0 }, +++ { 0x0, 0x0, "bgt", "r,r,la", "bgt %1,%2,%%pcrel(%3)", 0, 0, 0 }, +++ { 0x60000000, 0xfc000000, "bgt", "r0:5,r5:5,sb10:16<<2", 0, 0, 0, 0 }, +++ { 0x0, 0x0, "bge", "r,r,la", "bge %1,%2,%%pcrel(%3)", 0, 0, 0 }, +++ { 0x64000000, 0xfc000000, "bge", "r5:5,r0:5,sb10:16<<2", 0, 0, 0, 0 }, +++ { 0x0, 0x0, "ble", "r,r,la", "ble %1,%2,%%pcrel(%3)", 0, 0, 0 }, +++ { 0x64000000, 0xfc000000, "ble", "r0:5,r5:5,sb10:16<<2", 0, 0, 0, 0 }, +++ { 0x0, 0x0, "bltu", "r,r,la", "bltu %1,%2,%%pcrel(%3)", 0, 0, 0 }, +++ { 0x68000000, 0xfc000000, "bltu", "r5:5,r0:5,sb10:16<<2", 0, 0, 0, 0 }, +++ { 0x0, 0x0, "bgtu", "r,r,la", "bgtu %1,%2,%%pcrel(%3)", 0, 0, 0 }, +++ { 0x68000000, 0xfc000000, "bgtu", "r0:5,r5:5,sb10:16<<2", 0, 0, 0, 0 }, +++ { 0x0, 0x0, "bgeu", "r,r,la", "bgeu %1,%2,%%pcrel(%3)", 0, 0, 0 }, +++ { 0x6c000000, 0xfc000000, "bgeu", "r5:5,r0:5,sb10:16<<2", 0, 0, 0, 0 }, +++ { 0x0, 0x0, "bleu", "r,r,la", "bleu %1,%2,%%pcrel(%3)", 0, 0, 0 }, +++ { 0x6c000000, 0xfc000000, "bleu", "r0:5,r5:5,sb10:16<<2", 0, 0, 0, 0 }, +++ { 0 } /* Terminate the list. */ +++}; +++static struct loongarch_opcode loongarch_128vec_opcodes[] = { +++/* match, mask, name, format, macro, include, exclude, pinfo */ +++{0x2c000000, 0xffc00000, "vld", "v0:5,r5:5,s10:12", 0, 0, 0, 0}, +++{0x2c400000, 0xffc00000, "vst", "v0:5,r5:5,s10:12", 0, 0, 0, 0}, +++{0x30100000, 0xfff80000, "vldrepl.d", "v0:5,r5:5,s10:9<<3", 0, 0, 0, 0}, +++{0x30200000, 0xfff00000, "vldrepl.w", "v0:5,r5:5,s10:10<<2", 0, 0, 0, 0}, +++{0x30400000, 0xffe00000, "vldrepl.h", "v0:5,r5:5,s10:11<<1", 0, 0, 0, 0}, +++{0x30800000, 0xffc00000, "vldrepl.b", "v0:5,r5:5,s10:12", 0, 0, 0, 0}, +++{0x31100000, 0xfff80000, "vstelm.d", "v0:5,r5:5,s10:8<<3,u18:1", 0, 0, 0, 0}, +++{0x31200000, 0xfff00000, "vstelm.w", "v0:5,r5:5,s10:8<<2,u18:2", 0, 0, 0, 0}, +++{0x31400000, 0xffe00000, "vstelm.h", "v0:5,r5:5,s10:8<<1,u18:3", 0, 0, 0, 0}, +++{0x31800000, 0xffc00000, "vstelm.b", "v0:5,r5:5,s10:8,u18:4", 0, 0, 0, 0}, +++{0x38400000, 0xffff8000, "vldx", "v0:5,r5:5,r10:5", 0, 0, 0, 0}, +++{0x38440000, 0xffff8000, "vstx", "v0:5,r5:5,r10:5", 0, 0, 0, 0}, +++{0x70000000, 0xffff8000, "vseq.b", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70008000, 0xffff8000, "vseq.h", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70010000, 0xffff8000, "vseq.w", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70018000, 0xffff8000, "vseq.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70020000, 0xffff8000, "vsle.b", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70028000, 0xffff8000, "vsle.h", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70030000, 0xffff8000, "vsle.w", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70038000, 0xffff8000, "vsle.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70040000, 0xffff8000, "vsle.bu", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70048000, 0xffff8000, "vsle.hu", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70050000, 0xffff8000, "vsle.wu", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70058000, 0xffff8000, "vsle.du", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70060000, 0xffff8000, "vslt.b", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70068000, 0xffff8000, "vslt.h", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70070000, 0xffff8000, "vslt.w", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70078000, 0xffff8000, "vslt.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70080000, 0xffff8000, "vslt.bu", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70088000, 0xffff8000, "vslt.hu", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70090000, 0xffff8000, "vslt.wu", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70098000, 0xffff8000, "vslt.du", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x700a0000, 0xffff8000, "vadd.b", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x700a8000, 0xffff8000, "vadd.h", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x700b0000, 0xffff8000, "vadd.w", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x700b8000, 0xffff8000, "vadd.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x700c0000, 0xffff8000, "vsub.b", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x700c8000, 0xffff8000, "vsub.h", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x700d0000, 0xffff8000, "vsub.w", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x700d8000, 0xffff8000, "vsub.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70460000, 0xffff8000, "vsadd.b", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70468000, 0xffff8000, "vsadd.h", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70470000, 0xffff8000, "vsadd.w", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70478000, 0xffff8000, "vsadd.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70480000, 0xffff8000, "vssub.b", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70488000, 0xffff8000, "vssub.h", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70490000, 0xffff8000, "vssub.w", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70498000, 0xffff8000, "vssub.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x704a0000, 0xffff8000, "vsadd.bu", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x704a8000, 0xffff8000, "vsadd.hu", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x704b0000, 0xffff8000, "vsadd.wu", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x704b8000, 0xffff8000, "vsadd.du", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x704c0000, 0xffff8000, "vssub.bu", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x704c8000, 0xffff8000, "vssub.hu", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x704d0000, 0xffff8000, "vssub.wu", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x704d8000, 0xffff8000, "vssub.du", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70540000, 0xffff8000, "vhaddw.h.b", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70548000, 0xffff8000, "vhaddw.w.h", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70550000, 0xffff8000, "vhaddw.d.w", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70558000, 0xffff8000, "vhaddw.q.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70560000, 0xffff8000, "vhsubw.h.b", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70568000, 0xffff8000, "vhsubw.w.h", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70570000, 0xffff8000, "vhsubw.d.w", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70578000, 0xffff8000, "vhsubw.q.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70580000, 0xffff8000, "vhaddw.hu.bu", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70588000, 0xffff8000, "vhaddw.wu.hu", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70590000, 0xffff8000, "vhaddw.du.wu", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70598000, 0xffff8000, "vhaddw.qu.du", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x705a0000, 0xffff8000, "vhsubw.hu.bu", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x705a8000, 0xffff8000, "vhsubw.wu.hu", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x705b0000, 0xffff8000, "vhsubw.du.wu", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x705b8000, 0xffff8000, "vhsubw.qu.du", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x705c0000, 0xffff8000, "vadda.b", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x705c8000, 0xffff8000, "vadda.h", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x705d0000, 0xffff8000, "vadda.w", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x705d8000, 0xffff8000, "vadda.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70600000, 0xffff8000, "vabsd.b", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70608000, 0xffff8000, "vabsd.h", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70610000, 0xffff8000, "vabsd.w", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70618000, 0xffff8000, "vabsd.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70620000, 0xffff8000, "vabsd.bu", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70628000, 0xffff8000, "vabsd.hu", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70630000, 0xffff8000, "vabsd.wu", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70638000, 0xffff8000, "vabsd.du", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70640000, 0xffff8000, "vavg.b", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70648000, 0xffff8000, "vavg.h", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70650000, 0xffff8000, "vavg.w", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70658000, 0xffff8000, "vavg.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70660000, 0xffff8000, "vavg.bu", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70668000, 0xffff8000, "vavg.hu", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70670000, 0xffff8000, "vavg.wu", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70678000, 0xffff8000, "vavg.du", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70680000, 0xffff8000, "vavgr.b", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70688000, 0xffff8000, "vavgr.h", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70690000, 0xffff8000, "vavgr.w", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70698000, 0xffff8000, "vavgr.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x706a0000, 0xffff8000, "vavgr.bu", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x706a8000, 0xffff8000, "vavgr.hu", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x706b0000, 0xffff8000, "vavgr.wu", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x706b8000, 0xffff8000, "vavgr.du", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70700000, 0xffff8000, "vmax.b", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70708000, 0xffff8000, "vmax.h", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70710000, 0xffff8000, "vmax.w", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70718000, 0xffff8000, "vmax.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70720000, 0xffff8000, "vmin.b", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70728000, 0xffff8000, "vmin.h", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70730000, 0xffff8000, "vmin.w", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70738000, 0xffff8000, "vmin.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70740000, 0xffff8000, "vmax.bu", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70748000, 0xffff8000, "vmax.hu", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70750000, 0xffff8000, "vmax.wu", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70758000, 0xffff8000, "vmax.du", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70760000, 0xffff8000, "vmin.bu", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70768000, 0xffff8000, "vmin.hu", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70770000, 0xffff8000, "vmin.wu", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70778000, 0xffff8000, "vmin.du", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70840000, 0xffff8000, "vmul.b", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70848000, 0xffff8000, "vmul.h", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70850000, 0xffff8000, "vmul.w", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70858000, 0xffff8000, "vmul.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70860000, 0xffff8000, "vmuh.b", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70868000, 0xffff8000, "vmuh.h", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70870000, 0xffff8000, "vmuh.w", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70878000, 0xffff8000, "vmuh.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70880000, 0xffff8000, "vmuh.bu", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70888000, 0xffff8000, "vmuh.hu", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70890000, 0xffff8000, "vmuh.wu", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70898000, 0xffff8000, "vmuh.du", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70a80000, 0xffff8000, "vmadd.b", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70a88000, 0xffff8000, "vmadd.h", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70a90000, 0xffff8000, "vmadd.w", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70a98000, 0xffff8000, "vmadd.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70aa0000, 0xffff8000, "vmsub.b", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70aa8000, 0xffff8000, "vmsub.h", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70ab0000, 0xffff8000, "vmsub.w", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70ab8000, 0xffff8000, "vmsub.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70e00000, 0xffff8000, "vdiv.b", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70e08000, 0xffff8000, "vdiv.h", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70e10000, 0xffff8000, "vdiv.w", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70e18000, 0xffff8000, "vdiv.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70e20000, 0xffff8000, "vmod.b", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70e28000, 0xffff8000, "vmod.h", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70e30000, 0xffff8000, "vmod.w", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70e38000, 0xffff8000, "vmod.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70e40000, 0xffff8000, "vdiv.bu", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70e48000, 0xffff8000, "vdiv.hu", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70e50000, 0xffff8000, "vdiv.wu", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70e58000, 0xffff8000, "vdiv.du", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70e60000, 0xffff8000, "vmod.bu", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70e68000, 0xffff8000, "vmod.hu", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70e70000, 0xffff8000, "vmod.wu", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70e78000, 0xffff8000, "vmod.du", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70e80000, 0xffff8000, "vsll.b", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70e88000, 0xffff8000, "vsll.h", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70e90000, 0xffff8000, "vsll.w", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70e98000, 0xffff8000, "vsll.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70ea0000, 0xffff8000, "vsrl.b", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70ea8000, 0xffff8000, "vsrl.h", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70eb0000, 0xffff8000, "vsrl.w", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70eb8000, 0xffff8000, "vsrl.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70ec0000, 0xffff8000, "vsra.b", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70ec8000, 0xffff8000, "vsra.h", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70ed0000, 0xffff8000, "vsra.w", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70ed8000, 0xffff8000, "vsra.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70ee0000, 0xffff8000, "vrotr.b", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70ee8000, 0xffff8000, "vrotr.h", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70ef0000, 0xffff8000, "vrotr.w", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70ef8000, 0xffff8000, "vrotr.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70f00000, 0xffff8000, "vsrlr.b", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70f08000, 0xffff8000, "vsrlr.h", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70f10000, 0xffff8000, "vsrlr.w", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70f18000, 0xffff8000, "vsrlr.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70f20000, 0xffff8000, "vsrar.b", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70f28000, 0xffff8000, "vsrar.h", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70f30000, 0xffff8000, "vsrar.w", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70f38000, 0xffff8000, "vsrar.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70f48000, 0xffff8000, "vsrln.b.h", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70f50000, 0xffff8000, "vsrln.h.w", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70f58000, 0xffff8000, "vsrln.w.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70f68000, 0xffff8000, "vsran.b.h", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70f70000, 0xffff8000, "vsran.h.w", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70f78000, 0xffff8000, "vsran.w.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70f88000, 0xffff8000, "vsrlrn.b.h", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70f90000, 0xffff8000, "vsrlrn.h.w", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70f98000, 0xffff8000, "vsrlrn.w.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70fa8000, 0xffff8000, "vsrarn.b.h", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70fb0000, 0xffff8000, "vsrarn.h.w", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70fb8000, 0xffff8000, "vsrarn.w.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70fc8000, 0xffff8000, "vssrln.b.h", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70fd0000, 0xffff8000, "vssrln.h.w", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70fd8000, 0xffff8000, "vssrln.w.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70fe8000, 0xffff8000, "vssran.b.h", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70ff0000, 0xffff8000, "vssran.h.w", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70ff8000, 0xffff8000, "vssran.w.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x71008000, 0xffff8000, "vssrlrn.b.h", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x71010000, 0xffff8000, "vssrlrn.h.w", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x71018000, 0xffff8000, "vssrlrn.w.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x71028000, 0xffff8000, "vssrarn.b.h", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x71030000, 0xffff8000, "vssrarn.h.w", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x71038000, 0xffff8000, "vssrarn.w.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x71048000, 0xffff8000, "vssrln.bu.h", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x71050000, 0xffff8000, "vssrln.hu.w", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x71058000, 0xffff8000, "vssrln.wu.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x71068000, 0xffff8000, "vssran.bu.h", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x71070000, 0xffff8000, "vssran.hu.w", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x71078000, 0xffff8000, "vssran.wu.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x71088000, 0xffff8000, "vssrlrn.bu.h", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x71090000, 0xffff8000, "vssrlrn.hu.w", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x71098000, 0xffff8000, "vssrlrn.wu.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x710a8000, 0xffff8000, "vssrarn.bu.h", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x710b0000, 0xffff8000, "vssrarn.hu.w", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x710b8000, 0xffff8000, "vssrarn.wu.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x710c0000, 0xffff8000, "vbitclr.b", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x710c8000, 0xffff8000, "vbitclr.h", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x710d0000, 0xffff8000, "vbitclr.w", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x710d8000, 0xffff8000, "vbitclr.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x710e0000, 0xffff8000, "vbitset.b", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x710e8000, 0xffff8000, "vbitset.h", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x710f0000, 0xffff8000, "vbitset.w", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x710f8000, 0xffff8000, "vbitset.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x71100000, 0xffff8000, "vbitrev.b", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x71108000, 0xffff8000, "vbitrev.h", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x71110000, 0xffff8000, "vbitrev.w", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x71118000, 0xffff8000, "vbitrev.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x71160000, 0xffff8000, "vpackev.b", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x71168000, 0xffff8000, "vpackev.h", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x71170000, 0xffff8000, "vpackev.w", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x71178000, 0xffff8000, "vpackev.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x71180000, 0xffff8000, "vpackod.b", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x71188000, 0xffff8000, "vpackod.h", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x71190000, 0xffff8000, "vpackod.w", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x71198000, 0xffff8000, "vpackod.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x711a0000, 0xffff8000, "vilvl.b", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x711a8000, 0xffff8000, "vilvl.h", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x711b0000, 0xffff8000, "vilvl.w", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x711b8000, 0xffff8000, "vilvl.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x711c0000, 0xffff8000, "vilvh.b", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x711c8000, 0xffff8000, "vilvh.h", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x711d0000, 0xffff8000, "vilvh.w", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x711d8000, 0xffff8000, "vilvh.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x711e0000, 0xffff8000, "vpickev.b", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x711e8000, 0xffff8000, "vpickev.h", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x711f0000, 0xffff8000, "vpickev.w", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x711f8000, 0xffff8000, "vpickev.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x71200000, 0xffff8000, "vpickod.b", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x71208000, 0xffff8000, "vpickod.h", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x71210000, 0xffff8000, "vpickod.w", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x71218000, 0xffff8000, "vpickod.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x71220000, 0xffff8000, "vreplve.b", "v0:5,v5:5,r10:5", 0, 0, 0, 0}, +++{0x71228000, 0xffff8000, "vreplve.h", "v0:5,v5:5,r10:5", 0, 0, 0, 0}, +++{0x71230000, 0xffff8000, "vreplve.w", "v0:5,v5:5,r10:5", 0, 0, 0, 0}, +++{0x71238000, 0xffff8000, "vreplve.d", "v0:5,v5:5,r10:5", 0, 0, 0, 0}, +++{0x71260000, 0xffff8000, "vand.v", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x71268000, 0xffff8000, "vor.v", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x71270000, 0xffff8000, "vxor.v", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x71278000, 0xffff8000, "vnor.v", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x71280000, 0xffff8000, "vandn.v", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x71288000, 0xffff8000, "vorn.v", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x712b0000, 0xffff8000, "vfrstp.b", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x712b8000, 0xffff8000, "vfrstp.h", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x712d0000, 0xffff8000, "vadd.q", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x712d8000, 0xffff8000, "vsub.q", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x712e0000, 0xffff8000, "vsigncov.b", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x712e8000, 0xffff8000, "vsigncov.h", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x712f0000, 0xffff8000, "vsigncov.w", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x712f8000, 0xffff8000, "vsigncov.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x71308000, 0xffff8000, "vfadd.s", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x71310000, 0xffff8000, "vfadd.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x71328000, 0xffff8000, "vfsub.s", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x71330000, 0xffff8000, "vfsub.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x71388000, 0xffff8000, "vfmul.s", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x71390000, 0xffff8000, "vfmul.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x713a8000, 0xffff8000, "vfdiv.s", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x713b0000, 0xffff8000, "vfdiv.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x713c8000, 0xffff8000, "vfmax.s", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x713d0000, 0xffff8000, "vfmax.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x713e8000, 0xffff8000, "vfmin.s", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x713f0000, 0xffff8000, "vfmin.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x71408000, 0xffff8000, "vfmaxa.s", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x71410000, 0xffff8000, "vfmaxa.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x71428000, 0xffff8000, "vfmina.s", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x71430000, 0xffff8000, "vfmina.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x71460000, 0xffff8000, "vfcvt.h.s", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x71468000, 0xffff8000, "vfcvt.s.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x71480000, 0xffff8000, "vffint.s.l", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x71498000, 0xffff8000, "vftint.w.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x714a0000, 0xffff8000, "vftintrm.w.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x714a8000, 0xffff8000, "vftintrp.w.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x714b0000, 0xffff8000, "vftintrz.w.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x714b8000, 0xffff8000, "vftintrne.w.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x717a8000, 0xffff8000, "vshuf.h", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x717b0000, 0xffff8000, "vshuf.w", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x717b8000, 0xffff8000, "vshuf.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x72800000, 0xffff8000, "vseqi.b", "v0:5,v5:5,s10:5", 0, 0, 0, 0}, +++{0x72808000, 0xffff8000, "vseqi.h", "v0:5,v5:5,s10:5", 0, 0, 0, 0}, +++{0x72810000, 0xffff8000, "vseqi.w", "v0:5,v5:5,s10:5", 0, 0, 0, 0}, +++{0x72818000, 0xffff8000, "vseqi.d", "v0:5,v5:5,s10:5", 0, 0, 0, 0}, +++{0x72820000, 0xffff8000, "vslei.b", "v0:5,v5:5,s10:5", 0, 0, 0, 0}, +++{0x72828000, 0xffff8000, "vslei.h", "v0:5,v5:5,s10:5", 0, 0, 0, 0}, +++{0x72830000, 0xffff8000, "vslei.w", "v0:5,v5:5,s10:5", 0, 0, 0, 0}, +++{0x72838000, 0xffff8000, "vslei.d", "v0:5,v5:5,s10:5", 0, 0, 0, 0}, +++{0x72840000, 0xffff8000, "vslei.bu", "v0:5,v5:5,u10:5", 0, 0, 0, 0}, +++{0x72848000, 0xffff8000, "vslei.hu", "v0:5,v5:5,u10:5", 0, 0, 0, 0}, +++{0x72850000, 0xffff8000, "vslei.wu", "v0:5,v5:5,u10:5", 0, 0, 0, 0}, +++{0x72858000, 0xffff8000, "vslei.du", "v0:5,v5:5,u10:5", 0, 0, 0, 0}, +++{0x72860000, 0xffff8000, "vslti.b", "v0:5,v5:5,s10:5", 0, 0, 0, 0}, +++{0x72868000, 0xffff8000, "vslti.h", "v0:5,v5:5,s10:5", 0, 0, 0, 0}, +++{0x72870000, 0xffff8000, "vslti.w", "v0:5,v5:5,s10:5", 0, 0, 0, 0}, +++{0x72878000, 0xffff8000, "vslti.d", "v0:5,v5:5,s10:5", 0, 0, 0, 0}, +++{0x72880000, 0xffff8000, "vslti.bu", "v0:5,v5:5,u10:5", 0, 0, 0, 0}, +++{0x72888000, 0xffff8000, "vslti.hu", "v0:5,v5:5,u10:5", 0, 0, 0, 0}, +++{0x72890000, 0xffff8000, "vslti.wu", "v0:5,v5:5,u10:5", 0, 0, 0, 0}, +++{0x72898000, 0xffff8000, "vslti.du", "v0:5,v5:5,u10:5", 0, 0, 0, 0}, +++{0x728a0000, 0xffff8000, "vaddi.bu", "v0:5,v5:5,u10:5", 0, 0, 0, 0}, +++{0x728a8000, 0xffff8000, "vaddi.hu", "v0:5,v5:5,u10:5", 0, 0, 0, 0}, +++{0x728b0000, 0xffff8000, "vaddi.wu", "v0:5,v5:5,u10:5", 0, 0, 0, 0}, +++{0x728b8000, 0xffff8000, "vaddi.du", "v0:5,v5:5,u10:5", 0, 0, 0, 0}, +++{0x728c0000, 0xffff8000, "vsubi.bu", "v0:5,v5:5,u10:5", 0, 0, 0, 0}, +++{0x728c8000, 0xffff8000, "vsubi.hu", "v0:5,v5:5,u10:5", 0, 0, 0, 0}, +++{0x728d0000, 0xffff8000, "vsubi.wu", "v0:5,v5:5,u10:5", 0, 0, 0, 0}, +++{0x728d8000, 0xffff8000, "vsubi.du", "v0:5,v5:5,u10:5", 0, 0, 0, 0}, +++{0x728e0000, 0xffff8000, "vbsll.v", "v0:5,v5:5,u10:5", 0, 0, 0, 0}, +++{0x728e8000, 0xffff8000, "vbsrl.v", "v0:5,v5:5,u10:5", 0, 0, 0, 0}, +++{0x72900000, 0xffff8000, "vmaxi.b", "v0:5,v5:5,s10:5", 0, 0, 0, 0}, +++{0x72908000, 0xffff8000, "vmaxi.h", "v0:5,v5:5,s10:5", 0, 0, 0, 0}, +++{0x72910000, 0xffff8000, "vmaxi.w", "v0:5,v5:5,s10:5", 0, 0, 0, 0}, +++{0x72918000, 0xffff8000, "vmaxi.d", "v0:5,v5:5,s10:5", 0, 0, 0, 0}, +++{0x72920000, 0xffff8000, "vmini.b", "v0:5,v5:5,s10:5", 0, 0, 0, 0}, +++{0x72928000, 0xffff8000, "vmini.h", "v0:5,v5:5,s10:5", 0, 0, 0, 0}, +++{0x72930000, 0xffff8000, "vmini.w", "v0:5,v5:5,s10:5", 0, 0, 0, 0}, +++{0x72938000, 0xffff8000, "vmini.d", "v0:5,v5:5,s10:5", 0, 0, 0, 0}, +++{0x72940000, 0xffff8000, "vmaxi.bu", "v0:5,v5:5,u10:5", 0, 0, 0, 0}, +++{0x72948000, 0xffff8000, "vmaxi.hu", "v0:5,v5:5,u10:5", 0, 0, 0, 0}, +++{0x72950000, 0xffff8000, "vmaxi.wu", "v0:5,v5:5,u10:5", 0, 0, 0, 0}, +++{0x72958000, 0xffff8000, "vmaxi.du", "v0:5,v5:5,u10:5", 0, 0, 0, 0}, +++{0x72960000, 0xffff8000, "vmini.bu", "v0:5,v5:5,u10:5", 0, 0, 0, 0}, +++{0x72968000, 0xffff8000, "vmini.hu", "v0:5,v5:5,u10:5", 0, 0, 0, 0}, +++{0x72970000, 0xffff8000, "vmini.wu", "v0:5,v5:5,u10:5", 0, 0, 0, 0}, +++{0x72978000, 0xffff8000, "vmini.du", "v0:5,v5:5,u10:5", 0, 0, 0, 0}, +++{0x729a0000, 0xffff8000, "vfrstpi.b", "v0:5,v5:5,u10:5", 0, 0, 0, 0}, +++{0x729a8000, 0xffff8000, "vfrstpi.h", "v0:5,v5:5,u10:5", 0, 0, 0, 0}, +++{0x729c0000, 0xfffffc00, "vclo.b", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729c0400, 0xfffffc00, "vclo.h", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729c0800, 0xfffffc00, "vclo.w", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729c0c00, 0xfffffc00, "vclo.d", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729c1000, 0xfffffc00, "vclz.b", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729c1400, 0xfffffc00, "vclz.h", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729c1800, 0xfffffc00, "vclz.w", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729c1c00, 0xfffffc00, "vclz.d", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729c2000, 0xfffffc00, "vpcnt.b", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729c2400, 0xfffffc00, "vpcnt.h", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729c2800, 0xfffffc00, "vpcnt.w", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729c2c00, 0xfffffc00, "vpcnt.d", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729c3000, 0xfffffc00, "vneg.b", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729c3400, 0xfffffc00, "vneg.h", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729c3800, 0xfffffc00, "vneg.w", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729c3c00, 0xfffffc00, "vneg.d", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729c4000, 0xfffffc00, "vmskltz.b", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729c4400, 0xfffffc00, "vmskltz.h", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729c4800, 0xfffffc00, "vmskltz.w", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729c4c00, 0xfffffc00, "vmskltz.d", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729c5000, 0xfffffc00, "vmskgez.b", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729c6000, 0xfffffc00, "vmsknz.b", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729c9800, 0xfffffc18, "vseteqz.v", "c0:3,v5:5", 0, 0, 0, 0}, +++{0x729c9c00, 0xfffffc18, "vsetnez.v", "c0:3,v5:5", 0, 0, 0, 0}, +++{0x729ca000, 0xfffffc18, "vsetanyeqz.b", "c0:3,v5:5", 0, 0, 0, 0}, +++{0x729ca400, 0xfffffc18, "vsetanyeqz.h", "c0:3,v5:5", 0, 0, 0, 0}, +++{0x729ca800, 0xfffffc18, "vsetanyeqz.w", "c0:3,v5:5", 0, 0, 0, 0}, +++{0x729cac00, 0xfffffc18, "vsetanyeqz.d", "c0:3,v5:5", 0, 0, 0, 0}, +++{0x729cb000, 0xfffffc18, "vsetallnez.b", "c0:3,v5:5", 0, 0, 0, 0}, +++{0x729cb400, 0xfffffc18, "vsetallnez.h", "c0:3,v5:5", 0, 0, 0, 0}, +++{0x729cb800, 0xfffffc18, "vsetallnez.w", "c0:3,v5:5", 0, 0, 0, 0}, +++{0x729cbc00, 0xfffffc18, "vsetallnez.d", "c0:3,v5:5", 0, 0, 0, 0}, +++{0x729cc400, 0xfffffc00, "vflogb.s", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729cc800, 0xfffffc00, "vflogb.d", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729cd400, 0xfffffc00, "vfclass.s", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729cd800, 0xfffffc00, "vfclass.d", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729ce400, 0xfffffc00, "vfsqrt.s", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729ce800, 0xfffffc00, "vfsqrt.d", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729cf400, 0xfffffc00, "vfrecip.s", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729cf800, 0xfffffc00, "vfrecip.d", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729d0400, 0xfffffc00, "vfrsqrt.s", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729d0800, 0xfffffc00, "vfrsqrt.d", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729d3400, 0xfffffc00, "vfrint.s", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729d3800, 0xfffffc00, "vfrint.d", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729d4400, 0xfffffc00, "vfrintrm.s", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729d4800, 0xfffffc00, "vfrintrm.d", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729d5400, 0xfffffc00, "vfrintrp.s", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729d5800, 0xfffffc00, "vfrintrp.d", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729d6400, 0xfffffc00, "vfrintrz.s", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729d6800, 0xfffffc00, "vfrintrz.d", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729d7400, 0xfffffc00, "vfrintrne.s", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729d7800, 0xfffffc00, "vfrintrne.d", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729de800, 0xfffffc00, "vfcvtl.s.h", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729dec00, 0xfffffc00, "vfcvth.s.h", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729df000, 0xfffffc00, "vfcvtl.d.s", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729df400, 0xfffffc00, "vfcvth.d.s", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729e0000, 0xfffffc00, "vffint.s.w", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729e0400, 0xfffffc00, "vffint.s.wu", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729e0800, 0xfffffc00, "vffint.d.l", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729e0c00, 0xfffffc00, "vffint.d.lu", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729e1000, 0xfffffc00, "vffintl.d.w", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729e1400, 0xfffffc00, "vffinth.d.w", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729e3000, 0xfffffc00, "vftint.w.s", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729e3400, 0xfffffc00, "vftint.l.d", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729e3800, 0xfffffc00, "vftintrm.w.s", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729e3c00, 0xfffffc00, "vftintrm.l.d", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729e4000, 0xfffffc00, "vftintrp.w.s", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729e4400, 0xfffffc00, "vftintrp.l.d", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729e4800, 0xfffffc00, "vftintrz.w.s", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729e4c00, 0xfffffc00, "vftintrz.l.d", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729e5000, 0xfffffc00, "vftintrne.w.s", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729e5400, 0xfffffc00, "vftintrne.l.d", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729e5800, 0xfffffc00, "vftint.wu.s", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729e5c00, 0xfffffc00, "vftint.lu.d", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729e7000, 0xfffffc00, "vftintrz.wu.s", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729e7400, 0xfffffc00, "vftintrz.lu.d", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729e8000, 0xfffffc00, "vftintl.l.s", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729e8400, 0xfffffc00, "vftinth.l.s", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729e8800, 0xfffffc00, "vftintrml.l.s", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729e8c00, 0xfffffc00, "vftintrmh.l.s", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729e9000, 0xfffffc00, "vftintrpl.l.s", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729e9400, 0xfffffc00, "vftintrph.l.s", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729e9800, 0xfffffc00, "vftintrzl.l.s", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729e9c00, 0xfffffc00, "vftintrzh.l.s", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729ea000, 0xfffffc00, "vftintrnel.l.s", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729ea400, 0xfffffc00, "vftintrneh.l.s", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729ee000, 0xfffffc00, "vexth.h.b", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729ee400, 0xfffffc00, "vexth.w.h", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729ee800, 0xfffffc00, "vexth.d.w", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729eec00, 0xfffffc00, "vexth.q.d", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729ef000, 0xfffffc00, "vexth.hu.bu", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729ef400, 0xfffffc00, "vexth.wu.hu", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729ef800, 0xfffffc00, "vexth.du.wu", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729efc00, 0xfffffc00, "vexth.qu.du", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x729f0000, 0xfffffc00, "vreplgr2vr.b", "v0:5,r5:5", 0, 0, 0, 0}, +++{0x729f0400, 0xfffffc00, "vreplgr2vr.h", "v0:5,r5:5", 0, 0, 0, 0}, +++{0x729f0800, 0xfffffc00, "vreplgr2vr.w", "v0:5,r5:5", 0, 0, 0, 0}, +++{0x729f0c00, 0xfffffc00, "vreplgr2vr.d", "v0:5,r5:5", 0, 0, 0, 0}, +++{0x72a02000, 0xffffe000, "vrotri.b", "v0:5,v5:5,u10:3", 0, 0, 0, 0}, +++{0x72a04000, 0xffffc000, "vrotri.h", "v0:5,v5:5,u10:4", 0, 0, 0, 0}, +++{0x72a08000, 0xffff8000, "vrotri.w", "v0:5,v5:5,u10:5", 0, 0, 0, 0}, +++{0x72a10000, 0xffff0000, "vrotri.d", "v0:5,v5:5,u10:6", 0, 0, 0, 0}, +++{0x72a42000, 0xffffe000, "vsrlri.b", "v0:5,v5:5,u10:3", 0, 0, 0, 0}, +++{0x72a44000, 0xffffc000, "vsrlri.h", "v0:5,v5:5,u10:4", 0, 0, 0, 0}, +++{0x72a48000, 0xffff8000, "vsrlri.w", "v0:5,v5:5,u10:5", 0, 0, 0, 0}, +++{0x72a50000, 0xffff0000, "vsrlri.d", "v0:5,v5:5,u10:6", 0, 0, 0, 0}, +++{0x72a82000, 0xffffe000, "vsrari.b", "v0:5,v5:5,u10:3", 0, 0, 0, 0}, +++{0x72a84000, 0xffffc000, "vsrari.h", "v0:5,v5:5,u10:4", 0, 0, 0, 0}, +++{0x72a88000, 0xffff8000, "vsrari.w", "v0:5,v5:5,u10:5", 0, 0, 0, 0}, +++{0x72a90000, 0xffff0000, "vsrari.d", "v0:5,v5:5,u10:6", 0, 0, 0, 0}, +++{0x72eb8000, 0xffffc000, "vinsgr2vr.b", "v0:5,r5:5,u10:4", 0, 0, 0, 0}, +++{0x72ebc000, 0xffffe000, "vinsgr2vr.h", "v0:5,r5:5,u10:3", 0, 0, 0, 0}, +++{0x72ebe000, 0xfffff000, "vinsgr2vr.w", "v0:5,r5:5,u10:2", 0, 0, 0, 0}, +++{0x72ebf000, 0xfffff800, "vinsgr2vr.d", "v0:5,r5:5,u10:1", 0, 0, 0, 0}, +++{0x72ef8000, 0xffffc000, "vpickve2gr.b", "r0:5,v5:5,u10:4", 0, 0, 0, 0}, +++{0x72efc000, 0xffffe000, "vpickve2gr.h", "r0:5,v5:5,u10:3", 0, 0, 0, 0}, +++{0x72efe000, 0xfffff000, "vpickve2gr.w", "r0:5,v5:5,u10:2", 0, 0, 0, 0}, +++{0x72eff000, 0xfffff800, "vpickve2gr.d", "r0:5,v5:5,u10:1", 0, 0, 0, 0}, +++{0x72f38000, 0xffffc000, "vpickve2gr.bu", "r0:5,v5:5,u10:4", 0, 0, 0, 0}, +++{0x72f3c000, 0xffffe000, "vpickve2gr.hu", "r0:5,v5:5,u10:3", 0, 0, 0, 0}, +++{0x72f3e000, 0xfffff000, "vpickve2gr.wu", "r0:5,v5:5,u10:2", 0, 0, 0, 0}, +++{0x72f3f000, 0xfffff800, "vpickve2gr.du", "r0:5,v5:5,u10:1", 0, 0, 0, 0}, +++{0x72f78000, 0xffffc000, "vreplvei.b", "v0:5,v5:5,u10:4", 0, 0, 0, 0}, +++{0x72f7c000, 0xffffe000, "vreplvei.h", "v0:5,v5:5,u10:3", 0, 0, 0, 0}, +++{0x72f7e000, 0xfffff000, "vreplvei.w", "v0:5,v5:5,u10:2", 0, 0, 0, 0}, +++{0x72f7f000, 0xfffff800, "vreplvei.d", "v0:5,v5:5,u10:1", 0, 0, 0, 0}, +++{0x73082000, 0xffffe000, "vsllwil.h.b", "v0:5,v5:5,u10:3", 0, 0, 0, 0}, +++{0x73084000, 0xffffc000, "vsllwil.w.h", "v0:5,v5:5,u10:4", 0, 0, 0, 0}, +++{0x73088000, 0xffff8000, "vsllwil.d.w", "v0:5,v5:5,u10:5", 0, 0, 0, 0}, +++{0x73090000, 0xfffffc00, "vextl.q.d", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x730c2000, 0xffffe000, "vsllwil.hu.bu", "v0:5,v5:5,u10:3", 0, 0, 0, 0}, +++{0x730c4000, 0xffffc000, "vsllwil.wu.hu", "v0:5,v5:5,u10:4", 0, 0, 0, 0}, +++{0x730c8000, 0xffff8000, "vsllwil.du.wu", "v0:5,v5:5,u10:5", 0, 0, 0, 0}, +++{0x730d0000, 0xfffffc00, "vextl.qu.du", "v0:5,v5:5", 0, 0, 0, 0}, +++{0x73102000, 0xffffe000, "vbitclri.b", "v0:5,v5:5,u10:3", 0, 0, 0, 0}, +++{0x73104000, 0xffffc000, "vbitclri.h", "v0:5,v5:5,u10:4", 0, 0, 0, 0}, +++{0x73108000, 0xffff8000, "vbitclri.w", "v0:5,v5:5,u10:5", 0, 0, 0, 0}, +++{0x73110000, 0xffff0000, "vbitclri.d", "v0:5,v5:5,u10:6", 0, 0, 0, 0}, +++{0x73142000, 0xffffe000, "vbitseti.b", "v0:5,v5:5,u10:3", 0, 0, 0, 0}, +++{0x73144000, 0xffffc000, "vbitseti.h", "v0:5,v5:5,u10:4", 0, 0, 0, 0}, +++{0x73148000, 0xffff8000, "vbitseti.w", "v0:5,v5:5,u10:5", 0, 0, 0, 0}, +++{0x73150000, 0xffff0000, "vbitseti.d", "v0:5,v5:5,u10:6", 0, 0, 0, 0}, +++{0x73182000, 0xffffe000, "vbitrevi.b", "v0:5,v5:5,u10:3", 0, 0, 0, 0}, +++{0x73184000, 0xffffc000, "vbitrevi.h", "v0:5,v5:5,u10:4", 0, 0, 0, 0}, +++{0x73188000, 0xffff8000, "vbitrevi.w", "v0:5,v5:5,u10:5", 0, 0, 0, 0}, +++{0x73190000, 0xffff0000, "vbitrevi.d", "v0:5,v5:5,u10:6", 0, 0, 0, 0}, +++{0x73242000, 0xffffe000, "vsat.b", "v0:5,v5:5,u10:3", 0, 0, 0, 0}, +++{0x73244000, 0xffffc000, "vsat.h", "v0:5,v5:5,u10:4", 0, 0, 0, 0}, +++{0x73248000, 0xffff8000, "vsat.w", "v0:5,v5:5,u10:5", 0, 0, 0, 0}, +++{0x73250000, 0xffff0000, "vsat.d", "v0:5,v5:5,u10:6", 0, 0, 0, 0}, +++{0x73282000, 0xffffe000, "vsat.bu", "v0:5,v5:5,u10:3", 0, 0, 0, 0}, +++{0x73284000, 0xffffc000, "vsat.hu", "v0:5,v5:5,u10:4", 0, 0, 0, 0}, +++{0x73288000, 0xffff8000, "vsat.wu", "v0:5,v5:5,u10:5", 0, 0, 0, 0}, +++{0x73290000, 0xffff0000, "vsat.du", "v0:5,v5:5,u10:6", 0, 0, 0, 0}, +++{0x732c2000, 0xffffe000, "vslli.b", "v0:5,v5:5,u10:3", 0, 0, 0, 0}, +++{0x732c4000, 0xffffc000, "vslli.h", "v0:5,v5:5,u10:4", 0, 0, 0, 0}, +++{0x732c8000, 0xffff8000, "vslli.w", "v0:5,v5:5,u10:5", 0, 0, 0, 0}, +++{0x732d0000, 0xffff0000, "vslli.d", "v0:5,v5:5,u10:6", 0, 0, 0, 0}, +++{0x73302000, 0xffffe000, "vsrli.b", "v0:5,v5:5,u10:3", 0, 0, 0, 0}, +++{0x73304000, 0xffffc000, "vsrli.h", "v0:5,v5:5,u10:4", 0, 0, 0, 0}, +++{0x73308000, 0xffff8000, "vsrli.w", "v0:5,v5:5,u10:5", 0, 0, 0, 0}, +++{0x73310000, 0xffff0000, "vsrli.d", "v0:5,v5:5,u10:6", 0, 0, 0, 0}, +++{0x73342000, 0xffffe000, "vsrai.b", "v0:5,v5:5,u10:3", 0, 0, 0, 0}, +++{0x73344000, 0xffffc000, "vsrai.h", "v0:5,v5:5,u10:4", 0, 0, 0, 0}, +++{0x73348000, 0xffff8000, "vsrai.w", "v0:5,v5:5,u10:5", 0, 0, 0, 0}, +++{0x73350000, 0xffff0000, "vsrai.d", "v0:5,v5:5,u10:6", 0, 0, 0, 0}, +++{0x73404000, 0xffffc000, "vsrlni.b.h", "v0:5,v5:5,u10:4", 0, 0, 0, 0}, +++{0x73408000, 0xffff8000, "vsrlni.h.w", "v0:5,v5:5,u10:5", 0, 0, 0, 0}, +++{0x73410000, 0xffff0000, "vsrlni.w.d", "v0:5,v5:5,u10:6", 0, 0, 0, 0}, +++{0x73420000, 0xfffe0000, "vsrlni.d.q", "v0:5,v5:5,u10:7", 0, 0, 0, 0}, +++{0x73484000, 0xffffc000, "vssrlni.b.h", "v0:5,v5:5,u10:4", 0, 0, 0, 0}, +++{0x73488000, 0xffff8000, "vssrlni.h.w", "v0:5,v5:5,u10:5", 0, 0, 0, 0}, +++{0x73490000, 0xffff0000, "vssrlni.w.d", "v0:5,v5:5,u10:6", 0, 0, 0, 0}, +++{0x734a0000, 0xfffe0000, "vssrlni.d.q", "v0:5,v5:5,u10:7", 0, 0, 0, 0}, +++{0x73444000, 0xffffc000, "vsrlrni.b.h", "v0:5,v5:5,u10:4", 0, 0, 0, 0}, +++{0x73448000, 0xffff8000, "vsrlrni.h.w", "v0:5,v5:5,u10:5", 0, 0, 0, 0}, +++{0x73450000, 0xffff0000, "vsrlrni.w.d", "v0:5,v5:5,u10:6", 0, 0, 0, 0}, +++{0x73460000, 0xfffe0000, "vsrlrni.d.q", "v0:5,v5:5,u10:7", 0, 0, 0, 0}, +++{0x734c4000, 0xffffc000, "vssrlni.bu.h", "v0:5,v5:5,u10:4", 0, 0, 0, 0}, +++{0x734c8000, 0xffff8000, "vssrlni.hu.w", "v0:5,v5:5,u10:5", 0, 0, 0, 0}, +++{0x734d0000, 0xffff0000, "vssrlni.wu.d", "v0:5,v5:5,u10:6", 0, 0, 0, 0}, +++{0x734e0000, 0xfffe0000, "vssrlni.du.q", "v0:5,v5:5,u10:7", 0, 0, 0, 0}, +++{0x73504000, 0xffffc000, "vssrlrni.b.h", "v0:5,v5:5,u10:4", 0, 0, 0, 0}, +++{0x73508000, 0xffff8000, "vssrlrni.h.w", "v0:5,v5:5,u10:5", 0, 0, 0, 0}, +++{0x73510000, 0xffff0000, "vssrlrni.w.d", "v0:5,v5:5,u10:6", 0, 0, 0, 0}, +++{0x73520000, 0xfffe0000, "vssrlrni.d.q", "v0:5,v5:5,u10:7", 0, 0, 0, 0}, +++{0x73544000, 0xffffc000, "vssrlrni.bu.h", "v0:5,v5:5,u10:4", 0, 0, 0, 0}, +++{0x73548000, 0xffff8000, "vssrlrni.hu.w", "v0:5,v5:5,u10:5", 0, 0, 0, 0}, +++{0x73550000, 0xffff0000, "vssrlrni.wu.d", "v0:5,v5:5,u10:6", 0, 0, 0, 0}, +++{0x73560000, 0xfffe0000, "vssrlrni.du.q", "v0:5,v5:5,u10:7", 0, 0, 0, 0}, +++{0x73584000, 0xffffc000, "vsrani.b.h", "v0:5,v5:5,u10:4", 0, 0, 0, 0}, +++{0x73588000, 0xffff8000, "vsrani.h.w", "v0:5,v5:5,u10:5", 0, 0, 0, 0}, +++{0x73590000, 0xffff0000, "vsrani.w.d", "v0:5,v5:5,u10:6", 0, 0, 0, 0}, +++{0x735a0000, 0xfffe0000, "vsrani.d.q", "v0:5,v5:5,u10:7", 0, 0, 0, 0}, +++{0x735c4000, 0xffffc000, "vsrarni.b.h", "v0:5,v5:5,u10:4", 0, 0, 0, 0}, +++{0x735c8000, 0xffff8000, "vsrarni.h.w", "v0:5,v5:5,u10:5", 0, 0, 0, 0}, +++{0x735d0000, 0xffff0000, "vsrarni.w.d", "v0:5,v5:5,u10:6", 0, 0, 0, 0}, +++{0x735e0000, 0xfffe0000, "vsrarni.d.q", "v0:5,v5:5,u10:7", 0, 0, 0, 0}, +++{0x73604000, 0xffffc000, "vssrani.b.h", "v0:5,v5:5,u10:4", 0, 0, 0, 0}, +++{0x73608000, 0xffff8000, "vssrani.h.w", "v0:5,v5:5,u10:5", 0, 0, 0, 0}, +++{0x73610000, 0xffff0000, "vssrani.w.d", "v0:5,v5:5,u10:6", 0, 0, 0, 0}, +++{0x73620000, 0xfffe0000, "vssrani.d.q", "v0:5,v5:5,u10:7", 0, 0, 0, 0}, +++{0x73644000, 0xffffc000, "vssrani.bu.h", "v0:5,v5:5,u10:4", 0, 0, 0, 0}, +++{0x73648000, 0xffff8000, "vssrani.hu.w", "v0:5,v5:5,u10:5", 0, 0, 0, 0}, +++{0x73650000, 0xffff0000, "vssrani.wu.d", "v0:5,v5:5,u10:6", 0, 0, 0, 0}, +++{0x73660000, 0xfffe0000, "vssrani.du.q", "v0:5,v5:5,u10:7", 0, 0, 0, 0}, +++{0x73684000, 0xffffc000, "vssrarni.b.h", "v0:5,v5:5,u10:4", 0, 0, 0, 0}, +++{0x73688000, 0xffff8000, "vssrarni.h.w", "v0:5,v5:5,u10:5", 0, 0, 0, 0}, +++{0x73690000, 0xffff0000, "vssrarni.w.d", "v0:5,v5:5,u10:6", 0, 0, 0, 0}, +++{0x736a0000, 0xfffe0000, "vssrarni.d.q", "v0:5,v5:5,u10:7", 0, 0, 0, 0}, +++{0x736c4000, 0xffffc000, "vssrarni.bu.h", "v0:5,v5:5,u10:4", 0, 0, 0, 0}, +++{0x736c8000, 0xffff8000, "vssrarni.hu.w", "v0:5,v5:5,u10:5", 0, 0, 0, 0}, +++{0x736d0000, 0xffff0000, "vssrarni.wu.d", "v0:5,v5:5,u10:6", 0, 0, 0, 0}, +++{0x736e0000, 0xfffe0000, "vssrarni.du.q", "v0:5,v5:5,u10:7", 0, 0, 0, 0}, +++{0x73800000, 0xfffc0000, "vextrins.d", "v0:5,v5:5,u10:8", 0, 0, 0, 0}, +++{0x73840000, 0xfffc0000, "vextrins.w", "v0:5,v5:5,u10:8", 0, 0, 0, 0}, +++{0x73880000, 0xfffc0000, "vextrins.h", "v0:5,v5:5,u10:8", 0, 0, 0, 0}, +++{0x738c0000, 0xfffc0000, "vextrins.b", "v0:5,v5:5,u10:8", 0, 0, 0, 0}, +++{0x73900000, 0xfffc0000, "vshuf4i.b", "v0:5,v5:5,u10:8", 0, 0, 0, 0}, +++{0x73940000, 0xfffc0000, "vshuf4i.h", "v0:5,v5:5,u10:8", 0, 0, 0, 0}, +++{0x73980000, 0xfffc0000, "vshuf4i.w", "v0:5,v5:5,u10:8", 0, 0, 0, 0}, +++{0x739c0000, 0xfffc0000, "vshuf4i.d", "v0:5,v5:5,u10:8", 0, 0, 0, 0}, +++{0x73c40000, 0xfffc0000, "vbitseli.b", "v0:5,v5:5,u10:8", 0, 0, 0, 0}, +++{0x73d00000, 0xfffc0000, "vandi.b", "v0:5,v5:5,u10:8", 0, 0, 0, 0}, +++{0x73d40000, 0xfffc0000, "vori.b", "v0:5,v5:5,u10:8", 0, 0, 0, 0}, +++{0x73d80000, 0xfffc0000, "vxori.b", "v0:5,v5:5,u10:8", 0, 0, 0, 0}, +++{0x73dc0000, 0xfffc0000, "vnori.b", "v0:5,v5:5,u10:8", 0, 0, 0, 0}, +++{0, 0, "vrepli.b", "v,s0:10", "vldi %1,(%2)&0x3ff", 0, 0, 0}, +++ +++{0x701e0000, 0xffff8000, "vaddwev.h.b", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x701e8000, 0xffff8000, "vaddwev.w.h", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x701f0000, 0xffff8000, "vaddwev.d.w", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x701f8000, 0xffff8000, "vaddwev.q.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x702e0000, 0xffff8000, "vaddwev.h.bu", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x702e8000, 0xffff8000, "vaddwev.w.hu", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x702f0000, 0xffff8000, "vaddwev.d.wu", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x702f8000, 0xffff8000, "vaddwev.q.du", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x703e0000, 0xffff8000, "vaddwev.h.bu.b", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x703e8000, 0xffff8000, "vaddwev.w.hu.h", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x703f0000, 0xffff8000, "vaddwev.d.wu.w", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x703f8000, 0xffff8000, "vaddwev.q.du.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70220000, 0xffff8000, "vaddwod.h.b", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70228000, 0xffff8000, "vaddwod.w.h", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70230000, 0xffff8000, "vaddwod.d.w", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70238000, 0xffff8000, "vaddwod.q.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70320000, 0xffff8000, "vaddwod.h.bu", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70328000, 0xffff8000, "vaddwod.w.hu", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70330000, 0xffff8000, "vaddwod.d.wu", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70338000, 0xffff8000, "vaddwod.q.du", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70400000, 0xffff8000, "vaddwod.h.bu.b", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70408000, 0xffff8000, "vaddwod.w.hu.h", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70410000, 0xffff8000, "vaddwod.d.wu.w", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70418000, 0xffff8000, "vaddwod.q.du.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70ac0000, 0xffff8000, "vmaddwev.h.b", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70ac8000, 0xffff8000, "vmaddwev.w.h", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70ad0000, 0xffff8000, "vmaddwev.d.w", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70ad8000, 0xffff8000, "vmaddwev.q.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70b40000, 0xffff8000, "vmaddwev.h.bu", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70b48000, 0xffff8000, "vmaddwev.w.hu", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70b50000, 0xffff8000, "vmaddwev.d.wu", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70b58000, 0xffff8000, "vmaddwev.q.du", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70bc0000, 0xffff8000, "vmaddwev.h.bu.b", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70bc8000, 0xffff8000, "vmaddwev.w.hu.h", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70bd0000, 0xffff8000, "vmaddwev.d.wu.w", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70bd8000, 0xffff8000, "vmaddwev.q.du.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70ae0000, 0xffff8000, "vmaddwod.h.b", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70ae8000, 0xffff8000, "vmaddwod.w.h", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70af0000, 0xffff8000, "vmaddwod.d.w", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70af8000, 0xffff8000, "vmaddwod.q.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70b60000, 0xffff8000, "vmaddwod.h.bu", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70b68000, 0xffff8000, "vmaddwod.w.hu", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70b70000, 0xffff8000, "vmaddwod.d.wu", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70b78000, 0xffff8000, "vmaddwod.q.du", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70be0000, 0xffff8000, "vmaddwod.h.bu.b", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70be8000, 0xffff8000, "vmaddwod.w.hu.h", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70bf0000, 0xffff8000, "vmaddwod.d.wu.w", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70bf8000, 0xffff8000, "vmaddwod.q.du.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70900000, 0xffff8000, "vmulwev.h.b", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70908000, 0xffff8000, "vmulwev.w.h", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70910000, 0xffff8000, "vmulwev.d.w", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70918000, 0xffff8000, "vmulwev.q.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70980000, 0xffff8000, "vmulwev.h.bu", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70988000, 0xffff8000, "vmulwev.w.hu", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70990000, 0xffff8000, "vmulwev.d.wu", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70998000, 0xffff8000, "vmulwev.q.du", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70a00000, 0xffff8000, "vmulwev.h.bu.b", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70a08000, 0xffff8000, "vmulwev.w.hu.h", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70a10000, 0xffff8000, "vmulwev.d.wu.w", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70a18000, 0xffff8000, "vmulwev.q.du.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70920000, 0xffff8000, "vmulwod.h.b", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70928000, 0xffff8000, "vmulwod.w.h", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70930000, 0xffff8000, "vmulwod.d.w", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70938000, 0xffff8000, "vmulwod.q.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x709a0000, 0xffff8000, "vmulwod.h.bu", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x709a8000, 0xffff8000, "vmulwod.w.hu", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x709b0000, 0xffff8000, "vmulwod.d.wu", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x709b8000, 0xffff8000, "vmulwod.q.du", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70a20000, 0xffff8000, "vmulwod.h.bu.b", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70a28000, 0xffff8000, "vmulwod.w.hu.h", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70a30000, 0xffff8000, "vmulwod.d.wu.w", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70a38000, 0xffff8000, "vmulwod.q.du.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70200000, 0xffff8000, "vsubwev.h.b", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70208000, 0xffff8000, "vsubwev.w.h", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70210000, 0xffff8000, "vsubwev.d.w", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70218000, 0xffff8000, "vsubwev.q.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70300000, 0xffff8000, "vsubwev.h.bu", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70308000, 0xffff8000, "vsubwev.w.hu", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70310000, 0xffff8000, "vsubwev.d.wu", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70318000, 0xffff8000, "vsubwev.q.du", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70240000, 0xffff8000, "vsubwod.h.b", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70248000, 0xffff8000, "vsubwod.w.h", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70250000, 0xffff8000, "vsubwod.d.w", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70258000, 0xffff8000, "vsubwod.q.d", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70340000, 0xffff8000, "vsubwod.h.bu", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70348000, 0xffff8000, "vsubwod.w.hu", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70350000, 0xffff8000, "vsubwod.d.wu", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0x70358000, 0xffff8000, "vsubwod.q.du", "v0:5,v5:5,v10:5", 0, 0, 0, 0}, +++{0, 0, "vrepli.d", "v,s0:10", "vldi %1,((%2)&0x3ff)|0xc00", 0, 0, 0}, +++{0, 0, "vrepli.h", "v,s0:10", "vldi %1,((%2)&0x3ff)|0x400", 0, 0, 0}, +++{0, 0, "vrepli.w", "v,s0:10", "vldi %1,((%2)&0x3ff)|0x800", 0, 0, 0}, +++{0x73e00000, 0xfffc0000, "vldi", "v0:5,s5:13", 0, 0, 0, 0}, +++{0x73e40000, 0xfffc0000, "vpermi.w", "v0:5,v5:5,u10:8", 0, 0, 0, 0}, +++{0} /* Terminate the list. */ +++}; +++ +++static struct loongarch_opcode loongarch_256vec_opcodes[] = { +++/* match, mask, name, format, macro, include, exclude, pinfo */ +++{0x2c800000, 0xffc00000, "xvld", "x0:5,r5:5,s10:12", 0, 0, 0, 0}, +++{0x2cc00000, 0xffc00000, "xvst", "x0:5,r5:5,s10:12", 0, 0, 0, 0}, +++{0x32100000, 0xfff80000, "xvldrepl.d", "x0:5,r5:5,s10:9<<3", 0, 0, 0, 0}, +++{0x32200000, 0xfff00000, "xvldrepl.w", "x0:5,r5:5,s10:10<<2", 0, 0, 0, 0}, +++{0x32400000, 0xffe00000, "xvldrepl.h", "x0:5,r5:5,s10:11<<1", 0, 0, 0, 0}, +++{0x32800000, 0xffc00000, "xvldrepl.b", "x0:5,r5:5,s10:12", 0, 0, 0, 0}, +++{0x33100000, 0xfff00000, "xvstelm.d", "x0:5,r5:5,s10:8<<3,u18:2", 0, 0, 0, 0}, +++{0x33200000, 0xffe00000, "xvstelm.w", "x0:5,r5:5,s10:8<<2,u18:3", 0, 0, 0, 0}, +++{0x33400000, 0xffc00000, "xvstelm.h", "x0:5,r5:5,s10:8<<1,u18:4", 0, 0, 0, 0}, +++{0x33800000, 0xff800000, "xvstelm.b", "x0:5,r5:5,s10:8,u18:5", 0, 0, 0, 0}, +++{0x38480000, 0xffff8000, "xvldx", "x0:5,r5:5,r10:5", 0, 0, 0, 0}, +++{0x384c0000, 0xffff8000, "xvstx", "x0:5,r5:5,r10:5", 0, 0, 0, 0}, +++{0x74000000, 0xffff8000, "xvseq.b", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74008000, 0xffff8000, "xvseq.h", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74010000, 0xffff8000, "xvseq.w", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74018000, 0xffff8000, "xvseq.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74020000, 0xffff8000, "xvsle.b", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74028000, 0xffff8000, "xvsle.h", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74030000, 0xffff8000, "xvsle.w", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74038000, 0xffff8000, "xvsle.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74040000, 0xffff8000, "xvsle.bu", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74048000, 0xffff8000, "xvsle.hu", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74050000, 0xffff8000, "xvsle.wu", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74058000, 0xffff8000, "xvsle.du", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74060000, 0xffff8000, "xvslt.b", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74068000, 0xffff8000, "xvslt.h", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74070000, 0xffff8000, "xvslt.w", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74078000, 0xffff8000, "xvslt.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74080000, 0xffff8000, "xvslt.bu", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74088000, 0xffff8000, "xvslt.hu", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74090000, 0xffff8000, "xvslt.wu", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74098000, 0xffff8000, "xvslt.du", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x740a0000, 0xffff8000, "xvadd.b", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x740a8000, 0xffff8000, "xvadd.h", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x740b0000, 0xffff8000, "xvadd.w", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x740b8000, 0xffff8000, "xvadd.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x740c0000, 0xffff8000, "xvsub.b", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x740c8000, 0xffff8000, "xvsub.h", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x740d0000, 0xffff8000, "xvsub.w", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x740d8000, 0xffff8000, "xvsub.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74460000, 0xffff8000, "xvsadd.b", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74468000, 0xffff8000, "xvsadd.h", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74470000, 0xffff8000, "xvsadd.w", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74478000, 0xffff8000, "xvsadd.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74480000, 0xffff8000, "xvssub.b", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74488000, 0xffff8000, "xvssub.h", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74490000, 0xffff8000, "xvssub.w", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74498000, 0xffff8000, "xvssub.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x744a0000, 0xffff8000, "xvsadd.bu", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x744a8000, 0xffff8000, "xvsadd.hu", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x744b0000, 0xffff8000, "xvsadd.wu", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x744b8000, 0xffff8000, "xvsadd.du", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x744c0000, 0xffff8000, "xvssub.bu", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x744c8000, 0xffff8000, "xvssub.hu", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x744d0000, 0xffff8000, "xvssub.wu", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x744d8000, 0xffff8000, "xvssub.du", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74540000, 0xffff8000, "xvhaddw.h.b", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74548000, 0xffff8000, "xvhaddw.w.h", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74550000, 0xffff8000, "xvhaddw.d.w", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74558000, 0xffff8000, "xvhaddw.q.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74560000, 0xffff8000, "xvhsubw.h.b", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74568000, 0xffff8000, "xvhsubw.w.h", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74570000, 0xffff8000, "xvhsubw.d.w", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74578000, 0xffff8000, "xvhsubw.q.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74580000, 0xffff8000, "xvhaddw.hu.bu", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74588000, 0xffff8000, "xvhaddw.wu.hu", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74590000, 0xffff8000, "xvhaddw.du.wu", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74598000, 0xffff8000, "xvhaddw.qu.du", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x745a0000, 0xffff8000, "xvhsubw.hu.bu", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x745a8000, 0xffff8000, "xvhsubw.wu.hu", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x745b0000, 0xffff8000, "xvhsubw.du.wu", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x745b8000, 0xffff8000, "xvhsubw.qu.du", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x741e0000, 0xffff8000, "xvaddwev.h.b", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x741e8000, 0xffff8000, "xvaddwev.w.h", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x741f0000, 0xffff8000, "xvaddwev.d.w", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x741f8000, 0xffff8000, "xvaddwev.q.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x742e0000, 0xffff8000, "xvaddwev.h.bu", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x742e8000, 0xffff8000, "xvaddwev.w.hu", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x742f0000, 0xffff8000, "xvaddwev.d.wu", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x742f8000, 0xffff8000, "xvaddwev.q.du", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x743e0000, 0xffff8000, "xvaddwev.h.bu.b", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x743e8000, 0xffff8000, "xvaddwev.w.hu.h", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x743f0000, 0xffff8000, "xvaddwev.d.wu.w", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x743f8000, 0xffff8000, "xvaddwev.q.du.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74220000, 0xffff8000, "xvaddwod.h.b", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74228000, 0xffff8000, "xvaddwod.w.h", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74230000, 0xffff8000, "xvaddwod.d.w", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74238000, 0xffff8000, "xvaddwod.q.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74320000, 0xffff8000, "xvaddwod.h.bu", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74328000, 0xffff8000, "xvaddwod.w.hu", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74330000, 0xffff8000, "xvaddwod.d.wu", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74338000, 0xffff8000, "xvaddwod.q.du", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74400000, 0xffff8000, "xvaddwod.h.bu.b", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74408000, 0xffff8000, "xvaddwod.w.hu.h", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74410000, 0xffff8000, "xvaddwod.d.wu.w", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74418000, 0xffff8000, "xvaddwod.q.du.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74ac0000, 0xffff8000, "xvmaddwev.h.b", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74ac8000, 0xffff8000, "xvmaddwev.w.h", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74ad0000, 0xffff8000, "xvmaddwev.d.w", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74ad8000, 0xffff8000, "xvmaddwev.q.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74bc0000, 0xffff8000, "xvmaddwev.h.bu.b", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74bc8000, 0xffff8000, "xvmaddwev.w.hu.h", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74bd0000, 0xffff8000, "xvmaddwev.d.wu.w", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74bd8000, 0xffff8000, "xvmaddwev.q.du.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74b40000, 0xffff8000, "xvmaddwev.h.bu", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74b48000, 0xffff8000, "xvmaddwev.w.hu", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74b50000, 0xffff8000, "xvmaddwev.d.wu", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74b58000, 0xffff8000, "xvmaddwev.q.du", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74ae0000, 0xffff8000, "xvmaddwod.h.b", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74ae8000, 0xffff8000, "xvmaddwod.w.h", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74af0000, 0xffff8000, "xvmaddwod.d.w", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74af8000, 0xffff8000, "xvmaddwod.q.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74b60000, 0xffff8000, "xvmaddwod.h.bu", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74b68000, 0xffff8000, "xvmaddwod.w.hu", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74b70000, 0xffff8000, "xvmaddwod.d.wu", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74b78000, 0xffff8000, "xvmaddwod.q.du", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74be0000, 0xffff8000, "xvmaddwod.h.bu.b", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74be8000, 0xffff8000, "xvmaddwod.w.hu.h", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74bf0000, 0xffff8000, "xvmaddwod.d.wu.w", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74bf8000, 0xffff8000, "xvmaddwod.q.du.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74900000, 0xffff8000, "xvmulwev.h.b", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74908000, 0xffff8000, "xvmulwev.w.h", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74910000, 0xffff8000, "xvmulwev.d.w", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74918000, 0xffff8000, "xvmulwev.q.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74980000, 0xffff8000, "xvmulwev.h.bu", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74988000, 0xffff8000, "xvmulwev.w.hu", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74990000, 0xffff8000, "xvmulwev.d.wu", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74998000, 0xffff8000, "xvmulwev.q.du", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74a00000, 0xffff8000, "xvmulwev.h.bu.b", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74a08000, 0xffff8000, "xvmulwev.w.hu.h", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74a10000, 0xffff8000, "xvmulwev.d.wu.w", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74a18000, 0xffff8000, "xvmulwev.q.du.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74920000, 0xffff8000, "xvmulwod.h.b", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74928000, 0xffff8000, "xvmulwod.w.h", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74930000, 0xffff8000, "xvmulwod.d.w", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74938000, 0xffff8000, "xvmulwod.q.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x749a0000, 0xffff8000, "xvmulwod.h.bu", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x749a8000, 0xffff8000, "xvmulwod.w.hu", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x749b0000, 0xffff8000, "xvmulwod.d.wu", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x749b8000, 0xffff8000, "xvmulwod.q.du", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74a20000, 0xffff8000, "xvmulwod.h.bu.b", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74a28000, 0xffff8000, "xvmulwod.w.hu.h", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74a30000, 0xffff8000, "xvmulwod.d.wu.w", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74a38000, 0xffff8000, "xvmulwod.q.du.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74200000, 0xffff8000, "xvsubwev.h.b", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74208000, 0xffff8000, "xvsubwev.w.h", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74210000, 0xffff8000, "xvsubwev.d.w", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74218000, 0xffff8000, "xvsubwev.q.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74300000, 0xffff8000, "xvsubwev.h.bu", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74308000, 0xffff8000, "xvsubwev.w.hu", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74310000, 0xffff8000, "xvsubwev.d.wu", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74318000, 0xffff8000, "xvsubwev.q.du", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74240000, 0xffff8000, "xvsubwod.h.b", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74248000, 0xffff8000, "xvsubwod.w.h", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74250000, 0xffff8000, "xvsubwod.d.w", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74258000, 0xffff8000, "xvsubwod.q.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74340000, 0xffff8000, "xvsubwod.h.bu", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74348000, 0xffff8000, "xvsubwod.w.hu", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74350000, 0xffff8000, "xvsubwod.d.wu", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74358000, 0xffff8000, "xvsubwod.q.du", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x745c0000, 0xffff8000, "xvadda.b", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x745c8000, 0xffff8000, "xvadda.h", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x745d0000, 0xffff8000, "xvadda.w", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x745d8000, 0xffff8000, "xvadda.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74600000, 0xffff8000, "xvabsd.b", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74608000, 0xffff8000, "xvabsd.h", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74610000, 0xffff8000, "xvabsd.w", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74618000, 0xffff8000, "xvabsd.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74620000, 0xffff8000, "xvabsd.bu", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74628000, 0xffff8000, "xvabsd.hu", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74630000, 0xffff8000, "xvabsd.wu", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74638000, 0xffff8000, "xvabsd.du", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74640000, 0xffff8000, "xvavg.b", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74648000, 0xffff8000, "xvavg.h", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74650000, 0xffff8000, "xvavg.w", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74658000, 0xffff8000, "xvavg.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74660000, 0xffff8000, "xvavg.bu", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74668000, 0xffff8000, "xvavg.hu", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74670000, 0xffff8000, "xvavg.wu", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74678000, 0xffff8000, "xvavg.du", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74680000, 0xffff8000, "xvavgr.b", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74688000, 0xffff8000, "xvavgr.h", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74690000, 0xffff8000, "xvavgr.w", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74698000, 0xffff8000, "xvavgr.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x746a0000, 0xffff8000, "xvavgr.bu", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x746a8000, 0xffff8000, "xvavgr.hu", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x746b0000, 0xffff8000, "xvavgr.wu", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x746b8000, 0xffff8000, "xvavgr.du", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74700000, 0xffff8000, "xvmax.b", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74708000, 0xffff8000, "xvmax.h", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74710000, 0xffff8000, "xvmax.w", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74718000, 0xffff8000, "xvmax.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74720000, 0xffff8000, "xvmin.b", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74728000, 0xffff8000, "xvmin.h", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74730000, 0xffff8000, "xvmin.w", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74738000, 0xffff8000, "xvmin.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74740000, 0xffff8000, "xvmax.bu", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74748000, 0xffff8000, "xvmax.hu", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74750000, 0xffff8000, "xvmax.wu", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74758000, 0xffff8000, "xvmax.du", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74760000, 0xffff8000, "xvmin.bu", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74768000, 0xffff8000, "xvmin.hu", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74770000, 0xffff8000, "xvmin.wu", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74778000, 0xffff8000, "xvmin.du", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74840000, 0xffff8000, "xvmul.b", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74848000, 0xffff8000, "xvmul.h", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74850000, 0xffff8000, "xvmul.w", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74858000, 0xffff8000, "xvmul.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74860000, 0xffff8000, "xvmuh.b", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74868000, 0xffff8000, "xvmuh.h", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74870000, 0xffff8000, "xvmuh.w", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74878000, 0xffff8000, "xvmuh.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74880000, 0xffff8000, "xvmuh.bu", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74888000, 0xffff8000, "xvmuh.hu", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74890000, 0xffff8000, "xvmuh.wu", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74898000, 0xffff8000, "xvmuh.du", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74a80000, 0xffff8000, "xvmadd.b", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74a88000, 0xffff8000, "xvmadd.h", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74a90000, 0xffff8000, "xvmadd.w", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74a98000, 0xffff8000, "xvmadd.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74aa0000, 0xffff8000, "xvmsub.b", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74aa8000, 0xffff8000, "xvmsub.h", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74ab0000, 0xffff8000, "xvmsub.w", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74ab8000, 0xffff8000, "xvmsub.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74e00000, 0xffff8000, "xvdiv.b", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74e08000, 0xffff8000, "xvdiv.h", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74e10000, 0xffff8000, "xvdiv.w", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74e18000, 0xffff8000, "xvdiv.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74e20000, 0xffff8000, "xvmod.b", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74e28000, 0xffff8000, "xvmod.h", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74e30000, 0xffff8000, "xvmod.w", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74e38000, 0xffff8000, "xvmod.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74e40000, 0xffff8000, "xvdiv.bu", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74e48000, 0xffff8000, "xvdiv.hu", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74e50000, 0xffff8000, "xvdiv.wu", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74e58000, 0xffff8000, "xvdiv.du", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74e60000, 0xffff8000, "xvmod.bu", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74e68000, 0xffff8000, "xvmod.hu", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74e70000, 0xffff8000, "xvmod.wu", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74e78000, 0xffff8000, "xvmod.du", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74e80000, 0xffff8000, "xvsll.b", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74e88000, 0xffff8000, "xvsll.h", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74e90000, 0xffff8000, "xvsll.w", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74e98000, 0xffff8000, "xvsll.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74ea0000, 0xffff8000, "xvsrl.b", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74ea8000, 0xffff8000, "xvsrl.h", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74eb0000, 0xffff8000, "xvsrl.w", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74eb8000, 0xffff8000, "xvsrl.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74ec0000, 0xffff8000, "xvsra.b", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74ec8000, 0xffff8000, "xvsra.h", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74ed0000, 0xffff8000, "xvsra.w", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74ed8000, 0xffff8000, "xvsra.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74ee0000, 0xffff8000, "xvrotr.b", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74ee8000, 0xffff8000, "xvrotr.h", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74ef0000, 0xffff8000, "xvrotr.w", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74ef8000, 0xffff8000, "xvrotr.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74f00000, 0xffff8000, "xvsrlr.b", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74f08000, 0xffff8000, "xvsrlr.h", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74f10000, 0xffff8000, "xvsrlr.w", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74f18000, 0xffff8000, "xvsrlr.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74f20000, 0xffff8000, "xvsrar.b", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74f28000, 0xffff8000, "xvsrar.h", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74f30000, 0xffff8000, "xvsrar.w", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74f38000, 0xffff8000, "xvsrar.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74f48000, 0xffff8000, "xvsrln.b.h", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74f50000, 0xffff8000, "xvsrln.h.w", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74f58000, 0xffff8000, "xvsrln.w.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74f68000, 0xffff8000, "xvsran.b.h", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74f70000, 0xffff8000, "xvsran.h.w", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74f78000, 0xffff8000, "xvsran.w.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74f88000, 0xffff8000, "xvsrlrn.b.h", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74f90000, 0xffff8000, "xvsrlrn.h.w", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74f98000, 0xffff8000, "xvsrlrn.w.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74fa8000, 0xffff8000, "xvsrarn.b.h", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74fb0000, 0xffff8000, "xvsrarn.h.w", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74fb8000, 0xffff8000, "xvsrarn.w.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74fc8000, 0xffff8000, "xvssrln.b.h", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74fd0000, 0xffff8000, "xvssrln.h.w", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74fd8000, 0xffff8000, "xvssrln.w.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74fe8000, 0xffff8000, "xvssran.b.h", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74ff0000, 0xffff8000, "xvssran.h.w", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x74ff8000, 0xffff8000, "xvssran.w.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x75008000, 0xffff8000, "xvssrlrn.b.h", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x75010000, 0xffff8000, "xvssrlrn.h.w", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x75018000, 0xffff8000, "xvssrlrn.w.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x75028000, 0xffff8000, "xvssrarn.b.h", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x75030000, 0xffff8000, "xvssrarn.h.w", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x75038000, 0xffff8000, "xvssrarn.w.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x75048000, 0xffff8000, "xvssrln.bu.h", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x75050000, 0xffff8000, "xvssrln.hu.w", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x75058000, 0xffff8000, "xvssrln.wu.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x75068000, 0xffff8000, "xvssran.bu.h", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x75070000, 0xffff8000, "xvssran.hu.w", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x75078000, 0xffff8000, "xvssran.wu.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x75088000, 0xffff8000, "xvssrlrn.bu.h", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x75090000, 0xffff8000, "xvssrlrn.hu.w", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x75098000, 0xffff8000, "xvssrlrn.wu.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x750a8000, 0xffff8000, "xvssrarn.bu.h", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x750b0000, 0xffff8000, "xvssrarn.hu.w", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x750b8000, 0xffff8000, "xvssrarn.wu.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x750c0000, 0xffff8000, "xvbitclr.b", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x750c8000, 0xffff8000, "xvbitclr.h", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x750d0000, 0xffff8000, "xvbitclr.w", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x750d8000, 0xffff8000, "xvbitclr.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x750e0000, 0xffff8000, "xvbitset.b", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x750e8000, 0xffff8000, "xvbitset.h", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x750f0000, 0xffff8000, "xvbitset.w", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x750f8000, 0xffff8000, "xvbitset.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x75100000, 0xffff8000, "xvbitrev.b", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x75108000, 0xffff8000, "xvbitrev.h", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x75110000, 0xffff8000, "xvbitrev.w", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x75118000, 0xffff8000, "xvbitrev.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x75160000, 0xffff8000, "xvpackev.b", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x75168000, 0xffff8000, "xvpackev.h", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x75170000, 0xffff8000, "xvpackev.w", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x75178000, 0xffff8000, "xvpackev.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x75180000, 0xffff8000, "xvpackod.b", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x75188000, 0xffff8000, "xvpackod.h", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x75190000, 0xffff8000, "xvpackod.w", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x75198000, 0xffff8000, "xvpackod.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x751a0000, 0xffff8000, "xvilvl.b", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x751a8000, 0xffff8000, "xvilvl.h", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x751b0000, 0xffff8000, "xvilvl.w", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x751b8000, 0xffff8000, "xvilvl.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x751c0000, 0xffff8000, "xvilvh.b", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x751c8000, 0xffff8000, "xvilvh.h", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x751d0000, 0xffff8000, "xvilvh.w", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x751d8000, 0xffff8000, "xvilvh.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x751e0000, 0xffff8000, "xvpickev.b", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x751e8000, 0xffff8000, "xvpickev.h", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x751f0000, 0xffff8000, "xvpickev.w", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x751f8000, 0xffff8000, "xvpickev.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x75200000, 0xffff8000, "xvpickod.b", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x75208000, 0xffff8000, "xvpickod.h", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x75210000, 0xffff8000, "xvpickod.w", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x75218000, 0xffff8000, "xvpickod.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x75220000, 0xffff8000, "xvreplve.b", "x0:5,x5:5,r10:5", 0, 0, 0, 0}, +++{0x75228000, 0xffff8000, "xvreplve.h", "x0:5,x5:5,r10:5", 0, 0, 0, 0}, +++{0x75230000, 0xffff8000, "xvreplve.w", "x0:5,x5:5,r10:5", 0, 0, 0, 0}, +++{0x75238000, 0xffff8000, "xvreplve.d", "x0:5,x5:5,r10:5", 0, 0, 0, 0}, +++{0x75260000, 0xffff8000, "xvand.v", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x75268000, 0xffff8000, "xvor.v", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x75270000, 0xffff8000, "xvxor.v", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x75278000, 0xffff8000, "xvnor.v", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x75280000, 0xffff8000, "xvandn.v", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x75288000, 0xffff8000, "xvorn.v", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x752b0000, 0xffff8000, "xvfrstp.b", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x752b8000, 0xffff8000, "xvfrstp.h", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x752d0000, 0xffff8000, "xvadd.q", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x752d8000, 0xffff8000, "xvsub.q", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x752e0000, 0xffff8000, "xvsigncov.b", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x752e8000, 0xffff8000, "xvsigncov.h", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x752f0000, 0xffff8000, "xvsigncov.w", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x752f8000, 0xffff8000, "xvsigncov.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x75308000, 0xffff8000, "xvfadd.s", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x75310000, 0xffff8000, "xvfadd.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x75328000, 0xffff8000, "xvfsub.s", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x75330000, 0xffff8000, "xvfsub.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x75388000, 0xffff8000, "xvfmul.s", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x75390000, 0xffff8000, "xvfmul.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x753a8000, 0xffff8000, "xvfdiv.s", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x753b0000, 0xffff8000, "xvfdiv.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x753c8000, 0xffff8000, "xvfmax.s", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x753d0000, 0xffff8000, "xvfmax.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x753e8000, 0xffff8000, "xvfmin.s", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x753f0000, 0xffff8000, "xvfmin.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x75408000, 0xffff8000, "xvfmaxa.s", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x75410000, 0xffff8000, "xvfmaxa.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x75428000, 0xffff8000, "xvfmina.s", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x75430000, 0xffff8000, "xvfmina.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x75460000, 0xffff8000, "xvfcvt.h.s", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x75468000, 0xffff8000, "xvfcvt.s.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x75480000, 0xffff8000, "xvffint.s.l", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x75498000, 0xffff8000, "xvftint.w.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x754a0000, 0xffff8000, "xvftintrm.w.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x754a8000, 0xffff8000, "xvftintrp.w.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x754b0000, 0xffff8000, "xvftintrz.w.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x754b8000, 0xffff8000, "xvftintrne.w.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x757a8000, 0xffff8000, "xvshuf.h", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x757b0000, 0xffff8000, "xvshuf.w", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x757b8000, 0xffff8000, "xvshuf.d", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x757d0000, 0xffff8000, "xvperm.w", "x0:5,x5:5,x10:5", 0, 0, 0, 0}, +++{0x76800000, 0xffff8000, "xvseqi.b", "x0:5,x5:5,s10:5", 0, 0, 0, 0}, +++{0x76808000, 0xffff8000, "xvseqi.h", "x0:5,x5:5,s10:5", 0, 0, 0, 0}, +++{0x76810000, 0xffff8000, "xvseqi.w", "x0:5,x5:5,s10:5", 0, 0, 0, 0}, +++{0x76818000, 0xffff8000, "xvseqi.d", "x0:5,x5:5,s10:5", 0, 0, 0, 0}, +++{0x76820000, 0xffff8000, "xvslei.b", "x0:5,x5:5,s10:5", 0, 0, 0, 0}, +++{0x76828000, 0xffff8000, "xvslei.h", "x0:5,x5:5,s10:5", 0, 0, 0, 0}, +++{0x76830000, 0xffff8000, "xvslei.w", "x0:5,x5:5,s10:5", 0, 0, 0, 0}, +++{0x76838000, 0xffff8000, "xvslei.d", "x0:5,x5:5,s10:5", 0, 0, 0, 0}, +++{0x76840000, 0xffff8000, "xvslei.bu", "x0:5,x5:5,u10:5", 0, 0, 0, 0}, +++{0x76848000, 0xffff8000, "xvslei.hu", "x0:5,x5:5,u10:5", 0, 0, 0, 0}, +++{0x76850000, 0xffff8000, "xvslei.wu", "x0:5,x5:5,u10:5", 0, 0, 0, 0}, +++{0x76858000, 0xffff8000, "xvslei.du", "x0:5,x5:5,u10:5", 0, 0, 0, 0}, +++{0x76860000, 0xffff8000, "xvslti.b", "x0:5,x5:5,s10:5", 0, 0, 0, 0}, +++{0x76868000, 0xffff8000, "xvslti.h", "x0:5,x5:5,s10:5", 0, 0, 0, 0}, +++{0x76870000, 0xffff8000, "xvslti.w", "x0:5,x5:5,s10:5", 0, 0, 0, 0}, +++{0x76878000, 0xffff8000, "xvslti.d", "x0:5,x5:5,s10:5", 0, 0, 0, 0}, +++{0x76880000, 0xffff8000, "xvslti.bu", "x0:5,x5:5,u10:5", 0, 0, 0, 0}, +++{0x76888000, 0xffff8000, "xvslti.hu", "x0:5,x5:5,u10:5", 0, 0, 0, 0}, +++{0x76890000, 0xffff8000, "xvslti.wu", "x0:5,x5:5,u10:5", 0, 0, 0, 0}, +++{0x76898000, 0xffff8000, "xvslti.du", "x0:5,x5:5,u10:5", 0, 0, 0, 0}, +++{0x768a0000, 0xffff8000, "xvaddi.bu", "x0:5,x5:5,u10:5", 0, 0, 0, 0}, +++{0x768a8000, 0xffff8000, "xvaddi.hu", "x0:5,x5:5,u10:5", 0, 0, 0, 0}, +++{0x768b0000, 0xffff8000, "xvaddi.wu", "x0:5,x5:5,u10:5", 0, 0, 0, 0}, +++{0x768b8000, 0xffff8000, "xvaddi.du", "x0:5,x5:5,u10:5", 0, 0, 0, 0}, +++{0x768c0000, 0xffff8000, "xvsubi.bu", "x0:5,x5:5,u10:5", 0, 0, 0, 0}, +++{0x768c8000, 0xffff8000, "xvsubi.hu", "x0:5,x5:5,u10:5", 0, 0, 0, 0}, +++{0x768d0000, 0xffff8000, "xvsubi.wu", "x0:5,x5:5,u10:5", 0, 0, 0, 0}, +++{0x768d8000, 0xffff8000, "xvsubi.du", "x0:5,x5:5,u10:5", 0, 0, 0, 0}, +++{0x768e0000, 0xffff8000, "xvbsll.v", "x0:5,x5:5,u10:5", 0, 0, 0, 0}, +++{0x768e8000, 0xffff8000, "xvbsrl.v", "x0:5,x5:5,u10:5", 0, 0, 0, 0}, +++{0x76900000, 0xffff8000, "xvmaxi.b", "x0:5,x5:5,s10:5", 0, 0, 0, 0}, +++{0x76908000, 0xffff8000, "xvmaxi.h", "x0:5,x5:5,s10:5", 0, 0, 0, 0}, +++{0x76910000, 0xffff8000, "xvmaxi.w", "x0:5,x5:5,s10:5", 0, 0, 0, 0}, +++{0x76918000, 0xffff8000, "xvmaxi.d", "x0:5,x5:5,s10:5", 0, 0, 0, 0}, +++{0x76920000, 0xffff8000, "xvmini.b", "x0:5,x5:5,s10:5", 0, 0, 0, 0}, +++{0x76928000, 0xffff8000, "xvmini.h", "x0:5,x5:5,s10:5", 0, 0, 0, 0}, +++{0x76930000, 0xffff8000, "xvmini.w", "x0:5,x5:5,s10:5", 0, 0, 0, 0}, +++{0x76938000, 0xffff8000, "xvmini.d", "x0:5,x5:5,s10:5", 0, 0, 0, 0}, +++{0x76940000, 0xffff8000, "xvmaxi.bu", "x0:5,x5:5,u10:5", 0, 0, 0, 0}, +++{0x76948000, 0xffff8000, "xvmaxi.hu", "x0:5,x5:5,u10:5", 0, 0, 0, 0}, +++{0x76950000, 0xffff8000, "xvmaxi.wu", "x0:5,x5:5,u10:5", 0, 0, 0, 0}, +++{0x76958000, 0xffff8000, "xvmaxi.du", "x0:5,x5:5,u10:5", 0, 0, 0, 0}, +++{0x76960000, 0xffff8000, "xvmini.bu", "x0:5,x5:5,u10:5", 0, 0, 0, 0}, +++{0x76968000, 0xffff8000, "xvmini.hu", "x0:5,x5:5,u10:5", 0, 0, 0, 0}, +++{0x76970000, 0xffff8000, "xvmini.wu", "x0:5,x5:5,u10:5", 0, 0, 0, 0}, +++{0x76978000, 0xffff8000, "xvmini.du", "x0:5,x5:5,u10:5", 0, 0, 0, 0}, +++{0x769a0000, 0xffff8000, "xvfrstpi.b", "x0:5,x5:5,u10:5", 0, 0, 0, 0}, +++{0x769a8000, 0xffff8000, "xvfrstpi.h", "x0:5,x5:5,u10:5", 0, 0, 0, 0}, +++{0x769c0000, 0xfffffc00, "xvclo.b", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769c0400, 0xfffffc00, "xvclo.h", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769c0800, 0xfffffc00, "xvclo.w", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769c0c00, 0xfffffc00, "xvclo.d", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769c1000, 0xfffffc00, "xvclz.b", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769c1400, 0xfffffc00, "xvclz.h", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769c1800, 0xfffffc00, "xvclz.w", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769c1c00, 0xfffffc00, "xvclz.d", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769c2000, 0xfffffc00, "xvpcnt.b", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769c2400, 0xfffffc00, "xvpcnt.h", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769c2800, 0xfffffc00, "xvpcnt.w", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769c2c00, 0xfffffc00, "xvpcnt.d", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769c3000, 0xfffffc00, "xvneg.b", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769c3400, 0xfffffc00, "xvneg.h", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769c3800, 0xfffffc00, "xvneg.w", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769c3c00, 0xfffffc00, "xvneg.d", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769c4000, 0xfffffc00, "xvmskltz.b", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769c4400, 0xfffffc00, "xvmskltz.h", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769c4800, 0xfffffc00, "xvmskltz.w", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769c4c00, 0xfffffc00, "xvmskltz.d", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769c5000, 0xfffffc00, "xvmskgez.b", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769c6000, 0xfffffc00, "xvmsknz.b", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769c9800, 0xfffffc18, "xvseteqz.v", "c0:3,x5:5", 0, 0, 0, 0}, +++{0x769c9c00, 0xfffffc18, "xvsetnez.v", "c0:3,x5:5", 0, 0, 0, 0}, +++{0x769ca000, 0xfffffc18, "xvsetanyeqz.b", "c0:3,x5:5", 0, 0, 0, 0}, +++{0x769ca400, 0xfffffc18, "xvsetanyeqz.h", "c0:3,x5:5", 0, 0, 0, 0}, +++{0x769ca800, 0xfffffc18, "xvsetanyeqz.w", "c0:3,x5:5", 0, 0, 0, 0}, +++{0x769cac00, 0xfffffc18, "xvsetanyeqz.d", "c0:3,x5:5", 0, 0, 0, 0}, +++{0x769cb000, 0xfffffc18, "xvsetallnez.b", "c0:3,x5:5", 0, 0, 0, 0}, +++{0x769cb400, 0xfffffc18, "xvsetallnez.h", "c0:3,x5:5", 0, 0, 0, 0}, +++{0x769cb800, 0xfffffc18, "xvsetallnez.w", "c0:3,x5:5", 0, 0, 0, 0}, +++{0x769cbc00, 0xfffffc18, "xvsetallnez.d", "c0:3,x5:5", 0, 0, 0, 0}, +++{0x769cc400, 0xfffffc00, "xvflogb.s", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769cc800, 0xfffffc00, "xvflogb.d", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769cd400, 0xfffffc00, "xvfclass.s", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769cd800, 0xfffffc00, "xvfclass.d", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769ce400, 0xfffffc00, "xvfsqrt.s", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769ce800, 0xfffffc00, "xvfsqrt.d", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769cf400, 0xfffffc00, "xvfrecip.s", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769cf800, 0xfffffc00, "xvfrecip.d", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769d0400, 0xfffffc00, "xvfrsqrt.s", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769d0800, 0xfffffc00, "xvfrsqrt.d", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769d3400, 0xfffffc00, "xvfrint.s", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769d3800, 0xfffffc00, "xvfrint.d", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769d4400, 0xfffffc00, "xvfrintrm.s", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769d4800, 0xfffffc00, "xvfrintrm.d", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769d5400, 0xfffffc00, "xvfrintrp.s", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769d5800, 0xfffffc00, "xvfrintrp.d", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769d6400, 0xfffffc00, "xvfrintrz.s", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769d6800, 0xfffffc00, "xvfrintrz.d", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769d7400, 0xfffffc00, "xvfrintrne.s", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769d7800, 0xfffffc00, "xvfrintrne.d", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769de800, 0xfffffc00, "xvfcvtl.s.h", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769dec00, 0xfffffc00, "xvfcvth.s.h", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769df000, 0xfffffc00, "xvfcvtl.d.s", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769df400, 0xfffffc00, "xvfcvth.d.s", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769e0000, 0xfffffc00, "xvffint.s.w", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769e0400, 0xfffffc00, "xvffint.s.wu", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769e0800, 0xfffffc00, "xvffint.d.l", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769e0c00, 0xfffffc00, "xvffint.d.lu", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769e1000, 0xfffffc00, "xvffintl.d.w", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769e1400, 0xfffffc00, "xvffinth.d.w", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769e3000, 0xfffffc00, "xvftint.w.s", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769e3400, 0xfffffc00, "xvftint.l.d", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769e3800, 0xfffffc00, "xvftintrm.w.s", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769e3c00, 0xfffffc00, "xvftintrm.l.d", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769e4000, 0xfffffc00, "xvftintrp.w.s", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769e4400, 0xfffffc00, "xvftintrp.l.d", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769e4800, 0xfffffc00, "xvftintrz.w.s", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769e4c00, 0xfffffc00, "xvftintrz.l.d", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769e5000, 0xfffffc00, "xvftintrne.w.s", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769e5400, 0xfffffc00, "xvftintrne.l.d", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769e5800, 0xfffffc00, "xvftint.wu.s", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769e5c00, 0xfffffc00, "xvftint.lu.d", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769e7000, 0xfffffc00, "xvftintrz.wu.s", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769e7400, 0xfffffc00, "xvftintrz.lu.d", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769e8000, 0xfffffc00, "xvftintl.l.s", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769e8400, 0xfffffc00, "xvftinth.l.s", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769e8800, 0xfffffc00, "xvftintrml.l.s", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769e8c00, 0xfffffc00, "xvftintrmh.l.s", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769e9000, 0xfffffc00, "xvftintrpl.l.s", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769e9400, 0xfffffc00, "xvftintrph.l.s", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769e9800, 0xfffffc00, "xvftintrzl.l.s", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769e9c00, 0xfffffc00, "xvftintrzh.l.s", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769ea000, 0xfffffc00, "xvftintrnel.l.s", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769ea400, 0xfffffc00, "xvftintrneh.l.s", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769ee000, 0xfffffc00, "xvexth.h.b", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769ee400, 0xfffffc00, "xvexth.w.h", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769ee800, 0xfffffc00, "xvexth.d.w", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769eec00, 0xfffffc00, "xvexth.q.d", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769ef000, 0xfffffc00, "xvexth.hu.bu", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769ef400, 0xfffffc00, "xvexth.wu.hu", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769ef800, 0xfffffc00, "xvexth.du.wu", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769efc00, 0xfffffc00, "xvexth.qu.du", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769f0000, 0xfffffc00, "xvreplgr2vr.b", "x0:5,r5:5", 0, 0, 0, 0}, +++{0x769f0400, 0xfffffc00, "xvreplgr2vr.h", "x0:5,r5:5", 0, 0, 0, 0}, +++{0x769f0800, 0xfffffc00, "xvreplgr2vr.w", "x0:5,r5:5", 0, 0, 0, 0}, +++{0x769f0c00, 0xfffffc00, "xvreplgr2vr.d", "x0:5,r5:5", 0, 0, 0, 0}, +++{0x769f1000, 0xfffffc00, "vext2xv.h.b", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769f1400, 0xfffffc00, "vext2xv.w.b", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769f1800, 0xfffffc00, "vext2xv.d.b", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769f1c00, 0xfffffc00, "vext2xv.w.h", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769f2000, 0xfffffc00, "vext2xv.d.h", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769f2400, 0xfffffc00, "vext2xv.d.w", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769f2800, 0xfffffc00, "vext2xv.hu.bu", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769f2c00, 0xfffffc00, "vext2xv.wu.bu", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769f3000, 0xfffffc00, "vext2xv.du.bu", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769f3400, 0xfffffc00, "vext2xv.wu.hu", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769f3800, 0xfffffc00, "vext2xv.du.hu", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769f3c00, 0xfffffc00, "vext2xv.du.wu", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x769f8000, 0xffff8000, "xvhseli.d", "x0:5,x5:5,u10:5", 0, 0, 0, 0}, +++{0x76a02000, 0xffffe000, "xvrotri.b", "x0:5,x5:5,u10:3", 0, 0, 0, 0}, +++{0x76a04000, 0xffffc000, "xvrotri.h", "x0:5,x5:5,u10:4", 0, 0, 0, 0}, +++{0x76a08000, 0xffff8000, "xvrotri.w", "x0:5,x5:5,u10:5", 0, 0, 0, 0}, +++{0x76a10000, 0xffff0000, "xvrotri.d", "x0:5,x5:5,u10:6", 0, 0, 0, 0}, +++{0x76a42000, 0xffffe000, "xvsrlri.b", "x0:5,x5:5,u10:3", 0, 0, 0, 0}, +++{0x76a44000, 0xffffc000, "xvsrlri.h", "x0:5,x5:5,u10:4", 0, 0, 0, 0}, +++{0x76a48000, 0xffff8000, "xvsrlri.w", "x0:5,x5:5,u10:5", 0, 0, 0, 0}, +++{0x76a50000, 0xffff0000, "xvsrlri.d", "x0:5,x5:5,u10:6", 0, 0, 0, 0}, +++{0x76a82000, 0xffffe000, "xvsrari.b", "x0:5,x5:5,u10:3", 0, 0, 0, 0}, +++{0x76a84000, 0xffffc000, "xvsrari.h", "x0:5,x5:5,u10:4", 0, 0, 0, 0}, +++{0x76a88000, 0xffff8000, "xvsrari.w", "x0:5,x5:5,u10:5", 0, 0, 0, 0}, +++{0x76a90000, 0xffff0000, "xvsrari.d", "x0:5,x5:5,u10:6", 0, 0, 0, 0}, +++{0x76ebc000, 0xffffe000, "xvinsgr2vr.w", "x0:5,r5:5,u10:3", 0, 0, 0, 0}, +++{0x76ebe000, 0xfffff000, "xvinsgr2vr.d", "x0:5,r5:5,u10:2", 0, 0, 0, 0}, +++{0x76efc000, 0xffffe000, "xvpickve2gr.w", "r0:5,x5:5,u10:3", 0, 0, 0, 0}, +++{0x76efe000, 0xfffff000, "xvpickve2gr.d", "r0:5,x5:5,u10:2", 0, 0, 0, 0}, +++{0x76f3c000, 0xffffe000, "xvpickve2gr.wu", "r0:5,x5:5,u10:3", 0, 0, 0, 0}, +++{0x76f3e000, 0xfffff000, "xvpickve2gr.du", "r0:5,x5:5,u10:2", 0, 0, 0, 0}, +++{0x76f78000, 0xffffc000, "xvrepl128vei.b", "x0:5,x5:5,u10:4", 0, 0, 0, 0}, +++{0x76f7c000, 0xffffe000, "xvrepl128vei.h", "x0:5,x5:5,u10:3", 0, 0, 0, 0}, +++{0x76f7e000, 0xfffff000, "xvrepl128vei.w", "x0:5,x5:5,u10:2", 0, 0, 0, 0}, +++{0x76f7f000, 0xfffff800, "xvrepl128vei.d", "x0:5,x5:5,u10:1", 0, 0, 0, 0}, +++{0x76ffc000, 0xffffe000, "xvinsve0.w", "x0:5,x5:5,u10:3", 0, 0, 0, 0}, +++{0x76ffe000, 0xfffff000, "xvinsve0.d", "x0:5,x5:5,u10:2", 0, 0, 0, 0}, +++{0x7703c000, 0xffffe000, "xvpickve.w", "x0:5,x5:5,u10:3", 0, 0, 0, 0}, +++{0x7703e000, 0xfffff000, "xvpickve.d", "x0:5,x5:5,u10:2", 0, 0, 0, 0}, +++{0x77070000, 0xfffffc00, "xvreplve0.b", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x77078000, 0xfffffc00, "xvreplve0.h", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x7707c000, 0xfffffc00, "xvreplve0.w", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x7707e000, 0xfffffc00, "xvreplve0.d", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x7707f000, 0xfffffc00, "xvreplve0.q", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x77082000, 0xffffe000, "xvsllwil.h.b", "x0:5,x5:5,u10:3", 0, 0, 0, 0}, +++{0x77084000, 0xffffc000, "xvsllwil.w.h", "x0:5,x5:5,u10:4", 0, 0, 0, 0}, +++{0x77088000, 0xffff8000, "xvsllwil.d.w", "x0:5,x5:5,u10:5", 0, 0, 0, 0}, +++{0x77090000, 0xfffffc00, "xvextl.q.d", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x770c2000, 0xffffe000, "xvsllwil.hu.bu", "x0:5,x5:5,u10:3", 0, 0, 0, 0}, +++{0x770c4000, 0xffffc000, "xvsllwil.wu.hu", "x0:5,x5:5,u10:4", 0, 0, 0, 0}, +++{0x770c8000, 0xffff8000, "xvsllwil.du.wu", "x0:5,x5:5,u10:5", 0, 0, 0, 0}, +++{0x770d0000, 0xfffffc00, "xvextl.qu.du", "x0:5,x5:5", 0, 0, 0, 0}, +++{0x77102000, 0xffffe000, "xvbitclri.b", "x0:5,x5:5,u10:3", 0, 0, 0, 0}, +++{0x77104000, 0xffffc000, "xvbitclri.h", "x0:5,x5:5,u10:4", 0, 0, 0, 0}, +++{0x77108000, 0xffff8000, "xvbitclri.w", "x0:5,x5:5,u10:5", 0, 0, 0, 0}, +++{0x77110000, 0xffff0000, "xvbitclri.d", "x0:5,x5:5,u10:6", 0, 0, 0, 0}, +++{0x77142000, 0xffffe000, "xvbitseti.b", "x0:5,x5:5,u10:3", 0, 0, 0, 0}, +++{0x77144000, 0xffffc000, "xvbitseti.h", "x0:5,x5:5,u10:4", 0, 0, 0, 0}, +++{0x77148000, 0xffff8000, "xvbitseti.w", "x0:5,x5:5,u10:5", 0, 0, 0, 0}, +++{0x77150000, 0xffff0000, "xvbitseti.d", "x0:5,x5:5,u10:6", 0, 0, 0, 0}, +++{0x77182000, 0xffffe000, "xvbitrevi.b", "x0:5,x5:5,u10:3", 0, 0, 0, 0}, +++{0x77184000, 0xffffc000, "xvbitrevi.h", "x0:5,x5:5,u10:4", 0, 0, 0, 0}, +++{0x77188000, 0xffff8000, "xvbitrevi.w", "x0:5,x5:5,u10:5", 0, 0, 0, 0}, +++{0x77190000, 0xffff0000, "xvbitrevi.d", "x0:5,x5:5,u10:6", 0, 0, 0, 0}, +++{0x77242000, 0xffffe000, "xvsat.b", "x0:5,x5:5,u10:3", 0, 0, 0, 0}, +++{0x77244000, 0xffffc000, "xvsat.h", "x0:5,x5:5,u10:4", 0, 0, 0, 0}, +++{0x77248000, 0xffff8000, "xvsat.w", "x0:5,x5:5,u10:5", 0, 0, 0, 0}, +++{0x77250000, 0xffff0000, "xvsat.d", "x0:5,x5:5,u10:6", 0, 0, 0, 0}, +++{0x77282000, 0xffffe000, "xvsat.bu", "x0:5,x5:5,u10:3", 0, 0, 0, 0}, +++{0x77284000, 0xffffc000, "xvsat.hu", "x0:5,x5:5,u10:4", 0, 0, 0, 0}, +++{0x77288000, 0xffff8000, "xvsat.wu", "x0:5,x5:5,u10:5", 0, 0, 0, 0}, +++{0x77290000, 0xffff0000, "xvsat.du", "x0:5,x5:5,u10:6", 0, 0, 0, 0}, +++{0x772c2000, 0xffffe000, "xvslli.b", "x0:5,x5:5,u10:3", 0, 0, 0, 0}, +++{0x772c4000, 0xffffc000, "xvslli.h", "x0:5,x5:5,u10:4", 0, 0, 0, 0}, +++{0x772c8000, 0xffff8000, "xvslli.w", "x0:5,x5:5,u10:5", 0, 0, 0, 0}, +++{0x772d0000, 0xffff0000, "xvslli.d", "x0:5,x5:5,u10:6", 0, 0, 0, 0}, +++{0x77302000, 0xffffe000, "xvsrli.b", "x0:5,x5:5,u10:3", 0, 0, 0, 0}, +++{0x77304000, 0xffffc000, "xvsrli.h", "x0:5,x5:5,u10:4", 0, 0, 0, 0}, +++{0x77308000, 0xffff8000, "xvsrli.w", "x0:5,x5:5,u10:5", 0, 0, 0, 0}, +++{0x77310000, 0xffff0000, "xvsrli.d", "x0:5,x5:5,u10:6", 0, 0, 0, 0}, +++{0x77342000, 0xffffe000, "xvsrai.b", "x0:5,x5:5,u10:3", 0, 0, 0, 0}, +++{0x77344000, 0xffffc000, "xvsrai.h", "x0:5,x5:5,u10:4", 0, 0, 0, 0}, +++{0x77348000, 0xffff8000, "xvsrai.w", "x0:5,x5:5,u10:5", 0, 0, 0, 0}, +++{0x77350000, 0xffff0000, "xvsrai.d", "x0:5,x5:5,u10:6", 0, 0, 0, 0}, +++{0x77404000, 0xffffc000, "xvsrlni.b.h", "x0:5,x5:5,u10:4", 0, 0, 0, 0}, +++{0x77408000, 0xffff8000, "xvsrlni.h.w", "x0:5,x5:5,u10:5", 0, 0, 0, 0}, +++{0x77410000, 0xffff0000, "xvsrlni.w.d", "x0:5,x5:5,u10:6", 0, 0, 0, 0}, +++{0x77420000, 0xfffe0000, "xvsrlni.d.q", "x0:5,x5:5,u10:7", 0, 0, 0, 0}, +++{0x77444000, 0xffffc000, "xvsrlrni.b.h", "x0:5,x5:5,u10:4", 0, 0, 0, 0}, +++{0x77448000, 0xffff8000, "xvsrlrni.h.w", "x0:5,x5:5,u10:5", 0, 0, 0, 0}, +++{0x77450000, 0xffff0000, "xvsrlrni.w.d", "x0:5,x5:5,u10:6", 0, 0, 0, 0}, +++{0x77460000, 0xfffe0000, "xvsrlrni.d.q", "x0:5,x5:5,u10:7", 0, 0, 0, 0}, +++{0x77484000, 0xffffc000, "xvssrlni.b.h", "x0:5,x5:5,u10:4", 0, 0, 0, 0}, +++{0x77488000, 0xffff8000, "xvssrlni.h.w", "x0:5,x5:5,u10:5", 0, 0, 0, 0}, +++{0x77490000, 0xffff0000, "xvssrlni.w.d", "x0:5,x5:5,u10:6", 0, 0, 0, 0}, +++{0x774a0000, 0xfffe0000, "xvssrlni.d.q", "x0:5,x5:5,u10:7", 0, 0, 0, 0}, +++{0x774c4000, 0xffffc000, "xvssrlni.bu.h", "x0:5,x5:5,u10:4", 0, 0, 0, 0}, +++{0x774c8000, 0xffff8000, "xvssrlni.hu.w", "x0:5,x5:5,u10:5", 0, 0, 0, 0}, +++{0x774d0000, 0xffff0000, "xvssrlni.wu.d", "x0:5,x5:5,u10:6", 0, 0, 0, 0}, +++{0x774e0000, 0xfffe0000, "xvssrlni.du.q", "x0:5,x5:5,u10:7", 0, 0, 0, 0}, +++{0x77504000, 0xffffc000, "xvssrlrni.b.h", "x0:5,x5:5,u10:4", 0, 0, 0, 0}, +++{0x77508000, 0xffff8000, "xvssrlrni.h.w", "x0:5,x5:5,u10:5", 0, 0, 0, 0}, +++{0x77510000, 0xffff0000, "xvssrlrni.w.d", "x0:5,x5:5,u10:6", 0, 0, 0, 0}, +++{0x77520000, 0xfffe0000, "xvssrlrni.d.q", "x0:5,x5:5,u10:7", 0, 0, 0, 0}, +++{0x77544000, 0xffffc000, "xvssrlrni.bu.h", "x0:5,x5:5,u10:4", 0, 0, 0, 0}, +++{0x77548000, 0xffff8000, "xvssrlrni.hu.w", "x0:5,x5:5,u10:5", 0, 0, 0, 0}, +++{0x77550000, 0xffff0000, "xvssrlrni.wu.d", "x0:5,x5:5,u10:6", 0, 0, 0, 0}, +++{0x77560000, 0xfffe0000, "xvssrlrni.du.q", "x0:5,x5:5,u10:7", 0, 0, 0, 0}, +++{0x77584000, 0xffffc000, "xvsrani.b.h", "x0:5,x5:5,u10:4", 0, 0, 0, 0}, +++{0x77588000, 0xffff8000, "xvsrani.h.w", "x0:5,x5:5,u10:5", 0, 0, 0, 0}, +++{0x77590000, 0xffff0000, "xvsrani.w.d", "x0:5,x5:5,u10:6", 0, 0, 0, 0}, +++{0x775a0000, 0xfffe0000, "xvsrani.d.q", "x0:5,x5:5,u10:7", 0, 0, 0, 0}, +++{0x775c4000, 0xffffc000, "xvsrarni.b.h", "x0:5,x5:5,u10:4", 0, 0, 0, 0}, +++{0x775c8000, 0xffff8000, "xvsrarni.h.w", "x0:5,x5:5,u10:5", 0, 0, 0, 0}, +++{0x775d0000, 0xffff0000, "xvsrarni.w.d", "x0:5,x5:5,u10:6", 0, 0, 0, 0}, +++{0x775e0000, 0xfffe0000, "xvsrarni.d.q", "x0:5,x5:5,u10:7", 0, 0, 0, 0}, +++{0x77604000, 0xffffc000, "xvssrani.b.h", "x0:5,x5:5,u10:4", 0, 0, 0, 0}, +++{0x77608000, 0xffff8000, "xvssrani.h.w", "x0:5,x5:5,u10:5", 0, 0, 0, 0}, +++{0x77610000, 0xffff0000, "xvssrani.w.d", "x0:5,x5:5,u10:6", 0, 0, 0, 0}, +++{0x77620000, 0xfffe0000, "xvssrani.d.q", "x0:5,x5:5,u10:7", 0, 0, 0, 0}, +++{0x77644000, 0xffffc000, "xvssrani.bu.h", "x0:5,x5:5,u10:4", 0, 0, 0, 0}, +++{0x77648000, 0xffff8000, "xvssrani.hu.w", "x0:5,x5:5,u10:5", 0, 0, 0, 0}, +++{0x77650000, 0xffff0000, "xvssrani.wu.d", "x0:5,x5:5,u10:6", 0, 0, 0, 0}, +++{0x77660000, 0xfffe0000, "xvssrani.du.q", "x0:5,x5:5,u10:7", 0, 0, 0, 0}, +++{0x77684000, 0xffffc000, "xvssrarni.b.h", "x0:5,x5:5,u10:4", 0, 0, 0, 0}, +++{0x77688000, 0xffff8000, "xvssrarni.h.w", "x0:5,x5:5,u10:5", 0, 0, 0, 0}, +++{0x77690000, 0xffff0000, "xvssrarni.w.d", "x0:5,x5:5,u10:6", 0, 0, 0, 0}, +++{0x776a0000, 0xfffe0000, "xvssrarni.d.q", "x0:5,x5:5,u10:7", 0, 0, 0, 0}, +++{0x776c4000, 0xffffc000, "xvssrarni.bu.h", "x0:5,x5:5,u10:4", 0, 0, 0, 0}, +++{0x776c8000, 0xffff8000, "xvssrarni.hu.w", "x0:5,x5:5,u10:5", 0, 0, 0, 0}, +++{0x776d0000, 0xffff0000, "xvssrarni.wu.d", "x0:5,x5:5,u10:6", 0, 0, 0, 0}, +++{0x776e0000, 0xfffe0000, "xvssrarni.du.q", "x0:5,x5:5,u10:7", 0, 0, 0, 0}, +++{0x77800000, 0xfffc0000, "xvextrins.d", "x0:5,x5:5,u10:8", 0, 0, 0, 0}, +++{0x77840000, 0xfffc0000, "xvextrins.w", "x0:5,x5:5,u10:8", 0, 0, 0, 0}, +++{0x77880000, 0xfffc0000, "xvextrins.h", "x0:5,x5:5,u10:8", 0, 0, 0, 0}, +++{0x778c0000, 0xfffc0000, "xvextrins.b", "x0:5,x5:5,u10:8", 0, 0, 0, 0}, +++{0x77900000, 0xfffc0000, "xvshuf4i.b", "x0:5,x5:5,u10:8", 0, 0, 0, 0}, +++{0x77940000, 0xfffc0000, "xvshuf4i.h", "x0:5,x5:5,u10:8", 0, 0, 0, 0}, +++{0x77980000, 0xfffc0000, "xvshuf4i.w", "x0:5,x5:5,u10:8", 0, 0, 0, 0}, +++{0x779c0000, 0xfffc0000, "xvshuf4i.d", "x0:5,x5:5,u10:8", 0, 0, 0, 0}, +++{0x77c40000, 0xfffc0000, "xvbitseli.b", "x0:5,x5:5,u10:8", 0, 0, 0, 0}, +++{0x77d00000, 0xfffc0000, "xvandi.b", "x0:5,x5:5,u10:8", 0, 0, 0, 0}, +++{0x77d40000, 0xfffc0000, "xvori.b", "x0:5,x5:5,u10:8", 0, 0, 0, 0}, +++{0x77d80000, 0xfffc0000, "xvxori.b", "x0:5,x5:5,u10:8", 0, 0, 0, 0}, +++{0x77dc0000, 0xfffc0000, "xvnori.b", "x0:5,x5:5,u10:8", 0, 0, 0, 0}, +++{0, 0, "xvrepli.b", "x,s0:10", "xvldi %1,(%2)&0x3ff", 0, 0, 0}, +++{0, 0, "xvrepli.d", "x,s0:10", "xvldi %1,((%2)&0x3ff)|0xc00", 0, 0, 0}, +++{0, 0, "xvrepli.h", "x,s0:10", "xvldi %1,((%2)&0x3ff)|0x400", 0, 0, 0}, +++{0, 0, "xvrepli.w", "x,s0:10", "xvldi %1,((%2)&0x3ff)|0x800", 0, 0, 0}, +++{0x77e00000, 0xfffc0000, "xvldi", "x0:5,s5:13", 0, 0, 0, 0}, +++{0x77e40000, 0xfffc0000, "xvpermi.w", "x0:5,x5:5,u10:8", 0, 0, 0, 0}, +++{0x77e80000, 0xfffc0000, "xvpermi.d", "x0:5,x5:5,u10:8", 0, 0, 0, 0}, +++{0x77ec0000, 0xfffc0000, "xvpermi.q", "x0:5,x5:5,u10:8", 0, 0, 0, 0}, +++{0} /* Terminate the list. */ +++ +++}; +++ +++struct loongarch_ase loongarch_ASEs[] = { +++ {&LARCH_opts.ase_fix, loongarch_macro_opcodes, 0, 0, {0}, 0, 0}, +++ { &LARCH_opts.ase_fix, loongarch_lmm_opcodes, 0, 0, { 0 }, 0, 0 }, +++ { &LARCH_opts.ase_fix, loongarch_privilege_opcodes, 0, 0, { 0 }, 0, 0 }, +++ { &LARCH_opts.ase_fix, loongarch_load_store_opcodes, 0, 0, { 0 }, 0, 0 }, +++ { &LARCH_opts.ase_fix, loongarch_fix_opcodes, 0, 0, { 0 }, 0, 0 }, +++ { &LARCH_opts.ase_fix, loongarch_jmp_opcodes, 0, 0, { 0 }, 0, 0 }, +++ { &LARCH_opts.ase_float, loongarch_float_jmp_opcodes, 0, 0, { 0 }, 0, 0 }, +++ { &LARCH_opts.ase_float, loongarch_single_float_opcodes, 0, 0, { 0 }, 0, 0 }, +++ { &LARCH_opts.ase_float, loongarch_double_float_opcodes, 0, 0, { 0 }, 0, 0 }, +++ { &LARCH_opts.ase_float, loongarch_4opt_single_float_opcodes, 0, 0, { 0 }, 0, 0 }, +++ { &LARCH_opts.ase_float, loongarch_4opt_double_float_opcodes, 0, 0, { 0 }, 0, 0 }, +++ { &LARCH_opts.ase_float, loongarch_single_float_load_store_opcodes, 0, 0, { 0 }, 0, 0 }, +++ { &LARCH_opts.ase_float, loongarch_double_float_load_store_opcodes, 0, 0, { 0 }, 0, 0 }, +++ {&LARCH_opts.ase_128vec, loongarch_128vec_opcodes, 0, 0, {0}, 0, 0}, +++ {&LARCH_opts.ase_256vec, loongarch_256vec_opcodes, 0, 0, {0}, 0, 0}, +++ {0}, +++}; +++ ++-- ++2.27.0 ++ +diff --git a/gdb_interface.c b/gdb_interface.c +index 3a7fcc9..f5bc6f7 100644 +--- a/gdb_interface.c ++++ b/gdb_interface.c +@@ -961,7 +961,6 @@ gdb_error_debug(void) + + } + +- + /* + * gdb callback to access debug mode. + */ +diff --git a/lkcd_vmdump_v1.h b/lkcd_vmdump_v1.h +index 4933427..841f150 100644 +--- a/lkcd_vmdump_v1.h ++++ b/lkcd_vmdump_v1.h +@@ -118,10 +118,12 @@ typedef struct _dump_header_s { + #ifndef S390 + #ifndef S390X + #ifndef ARM64 ++#ifndef LOONGARCH64 + struct pt_regs dh_regs; + #endif + #endif + #endif ++#endif + #endif + + /* the address of the current task */ +diff --git a/lkcd_vmdump_v2_v3.h b/lkcd_vmdump_v2_v3.h +index 984c2c2..ab395ea 100644 +--- a/lkcd_vmdump_v2_v3.h ++++ b/lkcd_vmdump_v2_v3.h +@@ -37,7 +37,7 @@ + + #if defined(ARM) || defined(X86) || defined(PPC) || defined(S390) || \ + defined(S390X) || defined(ARM64) || defined(MIPS) || \ +- defined(MIPS64) || defined(SPARC64) ++ defined(MIPS64) || defined(SPARC64) || defined(LOONGARCH64) + + /* + * Kernel header file for Linux crash dumps. +@@ -87,10 +87,12 @@ typedef struct _dump_header_asm_s { + #ifndef S390 + #ifndef S390X + #ifndef ARM64 ++#ifndef LOONGARCH64 + struct pt_regs dha_regs; + #endif + #endif + #endif ++#endif + + } dump_header_asm_t; + +diff --git a/loongarch64.c b/loongarch64.c +new file mode 100644 +index 0000000..867bd05 +--- /dev/null ++++ b/loongarch64.c +@@ -0,0 +1,1344 @@ ++/* loongarch64.c - core analysis suite ++ * ++ * Copyright (C) 2021 Loongson Technology Co., Ltd. ++ * ++ * 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 2 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. ++ */ ++ ++#ifdef LOONGARCH64 ++ ++#include ++#include "defs.h" ++ ++static int loongarch64_pgd_vtop(ulong *pgd, ulong vaddr, ++ physaddr_t *paddr, int verbose); ++static int loongarch64_uvtop(struct task_context *tc, ulong vaddr, ++ physaddr_t *paddr, int verbose); ++static int loongarch64_kvtop(struct task_context *tc, ulong kvaddr, ++ physaddr_t *paddr, int verbose); ++static int loongarch64_translate_pte(ulong pte, void *physaddr, ++ ulonglong pte64); ++ ++static void loongarch64_cmd_mach(void); ++static void loongarch64_display_machine_stats(void); ++ ++static void loongarch64_back_trace_cmd(struct bt_info *bt); ++static void loongarch64_analyze_function(ulong start, ulong offset, ++ struct loongarch64_unwind_frame *current, ++ struct loongarch64_unwind_frame *previous); ++static void loongarch64_dump_backtrace_entry(struct bt_info *bt, ++ struct syment *sym, struct loongarch64_unwind_frame *current, ++ struct loongarch64_unwind_frame *previous, int level); ++static void loongarch64_dump_exception_stack(struct bt_info *bt, char *pt_regs); ++static int loongarch64_is_exception_entry(struct syment *sym); ++static void loongarch64_display_full_frame(struct bt_info *bt, ++ struct loongarch64_unwind_frame *current, ++ struct loongarch64_unwind_frame *previous); ++static void loongarch64_stackframe_init(void); ++static void loongarch64_get_stack_frame(struct bt_info *bt, ulong *pcp, ulong *spp); ++static int loongarch64_get_dumpfile_stack_frame(struct bt_info *bt, ++ ulong *nip, ulong *ksp); ++static int loongarch64_get_frame(struct bt_info *bt, ulong *pcp, ulong *spp); ++static int loongarch64_init_active_task_regs(void); ++static int loongarch64_get_crash_notes(void); ++static int loongarch64_get_elf_notes(void); ++ ++/* ++ * 3 Levels paging PAGE_SIZE=16KB ++ * PGD | PMD | PTE | OFFSET | ++ * 11 | 11 | 11 | 14 | ++ */ ++/* From arch/loongarch/include/asm/pgtable{,-64}.h */ ++typedef struct { ulong pgd; } pgd_t; ++typedef struct { ulong pmd; } pmd_t; ++typedef struct { ulong pte; } pte_t; ++ ++#define TASK_SIZE64 (1UL << 40) ++ ++#define PMD_ORDER 0 ++#define PTE_ORDER 0 ++ ++#define PMD_SHIFT (PAGESHIFT() + (PAGESHIFT() + PTE_ORDER - 3)) ++#define PMD_SIZE (1UL << PMD_SHIFT) ++#define PMD_MASK (~(PMD_SIZE - 1)) ++ ++#define PGDIR_SHIFT (PMD_SHIFT + (PAGESHIFT() + PMD_ORDER - 3)) ++#define PGDIR_SIZE (1UL << PGDIR_SHIFT) ++#define PGDIR_MASK (~(PGDIR_SIZE - 1)) ++ ++#define PTRS_PER_PTE (1UL << (PAGESHIFT() - 3)) ++#define PTRS_PER_PMD PTRS_PER_PTE ++#define PTRS_PER_PGD PTRS_PER_PTE ++#define USER_PTRS_PER_PGD ((TASK_SIZE64 / PGDIR_SIZE)?(TASK_SIZE64 / PGDIR_SIZE) : 1) ++ ++#define pte_index(addr) (((addr) >> PAGESHIFT()) & (PTRS_PER_PTE - 1)) ++#define pmd_index(addr) (((addr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1)) ++#define pgd_index(addr) (((addr) >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1)) ++ ++#define LOONGARCH64_CPU_RIXI (1UL << 23) /* CPU has TLB Read/eXec Inhibit */ ++ ++#define LOONGARCH64_EF_R0 0 ++#define LOONGARCH64_EF_RA 1 ++#define LOONGARCH64_EF_SP 3 ++#define LOONGARCH64_EF_FP 22 ++#define LOONGARCH64_EF_CSR_EPC 32 ++#define LOONGARCH64_EF_CSR_BADVADDR 33 ++#define LOONGARCH64_EF_CSR_CRMD 34 ++#define LOONGARCH64_EF_CSR_PRMD 35 ++#define LOONGARCH64_EF_CSR_EUEN 36 ++#define LOONGARCH64_EF_CSR_ECFG 37 ++#define LOONGARCH64_EF_CSR_ESTAT 38 ++ ++static struct machine_specific loongarch64_machine_specific = { 0 }; ++ ++/* ++ * Holds registers during the crash. ++ */ ++static struct loongarch64_pt_regs *panic_task_regs; ++ ++/* ++ * Check and print the flags on the page ++ */ ++static void ++check_page_flags(ulong pte) ++{ ++#define CHECK_PAGE_FLAG(flag) \ ++ if ((_PAGE_##flag) && (pte & _PAGE_##flag)) \ ++ fprintf(fp, "%s" #flag, others++ ? "|" : "") ++ ++ int others = 0; ++ fprintf(fp, "("); ++ ++ if (pte) { ++ CHECK_PAGE_FLAG(VALID); ++ CHECK_PAGE_FLAG(DIRTY); ++ CHECK_PAGE_FLAG(PLV); ++ ++ /* Determine whether it is a huge page format */ ++ if (pte & _PAGE_HGLOBAL) { ++ CHECK_PAGE_FLAG(HUGE); ++ CHECK_PAGE_FLAG(HGLOBAL); ++ } else { ++ CHECK_PAGE_FLAG(GLOBAL); ++ } ++ ++ CHECK_PAGE_FLAG(PRESENT); ++ CHECK_PAGE_FLAG(WRITE); ++ CHECK_PAGE_FLAG(PROTNONE); ++ CHECK_PAGE_FLAG(SPECIAL); ++ CHECK_PAGE_FLAG(NO_READ); ++ CHECK_PAGE_FLAG(NO_EXEC); ++ CHECK_PAGE_FLAG(RPLV); ++ } else { ++ fprintf(fp, "no mapping"); ++ } ++ ++ fprintf(fp, ")\n"); ++} ++ ++/* ++ * Translate a PTE, returning TRUE if the page is present. ++ * If a physaddr pointer is passed in, don't print anything. ++ */ ++static int ++loongarch64_translate_pte(ulong pte, void *physaddr, ulonglong unused) ++{ ++ char ptebuf[BUFSIZE]; ++ char physbuf[BUFSIZE]; ++ char buf1[BUFSIZE]; ++ char buf2[BUFSIZE]; ++ char buf3[BUFSIZE]; ++ char *arglist[MAXARGS]; ++ int page_present; ++ int c, len1, len2, len3; ++ ulong paddr; ++ ++ paddr = PTOB(pte >> _PFN_SHIFT); ++ page_present = !!(pte & _PAGE_PRESENT); ++ ++ if (physaddr) { ++ *(ulong *)physaddr = paddr; ++ return page_present; ++ } ++ ++ sprintf(ptebuf, "%lx", pte); ++ len1 = MAX(strlen(ptebuf), strlen("PTE")); ++ fprintf(fp, "%s ", mkstring(buf1, len1, CENTER | LJUST, "PTE")); ++ ++ if (!page_present) { ++ swap_location(pte, buf1); ++ if ((c = parse_line(buf1, arglist)) != 3) ++ error(FATAL, "cannot determine swap location\n"); ++ ++ len2 = MAX(strlen(arglist[0]), strlen("SWAP")); ++ len3 = MAX(strlen(arglist[2]), strlen("OFFSET")); ++ ++ fprintf(fp, "%s %s\n", ++ mkstring(buf2, len2, CENTER|LJUST, "SWAP"), ++ mkstring(buf3, len3, CENTER|LJUST, "OFFSET")); ++ ++ strcpy(buf2, arglist[0]); ++ strcpy(buf3, arglist[2]); ++ fprintf(fp, "%s %s %s\n", ++ mkstring(ptebuf, len1, CENTER|RJUST, NULL), ++ mkstring(buf2, len2, CENTER|RJUST, NULL), ++ mkstring(buf3, len3, CENTER|RJUST, NULL)); ++ return page_present; ++ } ++ ++ sprintf(physbuf, "%lx", paddr); ++ len2 = MAX(strlen(physbuf), strlen("PHYSICAL")); ++ fprintf(fp, "%s ", mkstring(buf1, len2, CENTER | LJUST, "PHYSICAL")); ++ ++ fprintf(fp, "FLAGS\n"); ++ fprintf(fp, "%s %s ", ++ mkstring(ptebuf, len1, CENTER | RJUST, NULL), ++ mkstring(physbuf, len2, CENTER | RJUST, NULL)); ++ ++ check_page_flags(pte); ++ ++ return page_present; ++} ++ ++/* ++ * Identify and print the segment name to which the virtual address belongs ++ */ ++static void ++get_segment_name(ulong vaddr, int verbose) ++{ ++ const char * segment; ++ ++ if (verbose) { ++ if (vaddr < 0x4000000000000000lu) ++ segment = "xuvrange"; ++ else if (vaddr < 0x8000000000000000lu) ++ segment = "xsprange"; ++ else if (vaddr < 0xc000000000000000lu) ++ segment = "xkprange"; ++ else ++ segment = "xkvrange"; ++ ++ fprintf(fp, "SEGMENT: %s\n", segment); ++ } ++} ++ ++/* ++ * Virtual to physical memory translation. This function will be called ++ * by both loongarch64_kvtop and loongarch64_uvtop. ++ */ ++static int ++loongarch64_pgd_vtop(ulong *pgd, ulong vaddr, physaddr_t *paddr, int verbose) ++{ ++ ulong *pgd_ptr, pgd_val; ++ ulong *pmd_ptr, pmd_val; ++ ulong *pte_ptr, pte_val; ++ ++ get_segment_name(vaddr, verbose); ++ ++ if (IS_XKPRANGE(vaddr)) { ++ *paddr = VTOP(vaddr); ++ return TRUE; ++ } ++ ++ if (verbose) ++ fprintf(fp, "PAGE DIRECTORY: %016lx\n", (ulong)pgd); ++ ++ pgd_ptr = pgd + pgd_index(vaddr); ++ FILL_PGD(PAGEBASE(pgd), KVADDR, PAGESIZE()); ++ pgd_val = ULONG(machdep->pgd + PAGEOFFSET(pgd_ptr)); ++ if (verbose) ++ fprintf(fp, " PGD: %16lx => %16lx\n", (ulong)pgd_ptr, pgd_val); ++ if (!pgd_val) ++ goto no_page; ++ ++ pmd_ptr = (ulong *)(VTOP(pgd_val) + sizeof(pmd_t) * pmd_index(vaddr)); ++ FILL_PMD(PAGEBASE(pmd_ptr), PHYSADDR, PAGESIZE()); ++ pmd_val = ULONG(machdep->pmd + PAGEOFFSET(pmd_ptr)); ++ if (verbose) ++ fprintf(fp, " PMD: %016lx => %016lx\n", (ulong)pmd_ptr, pmd_val); ++ if (!pmd_val) ++ goto no_page; ++ ++ pte_ptr = (ulong *)(VTOP(pmd_val) + sizeof(pte_t) * pte_index(vaddr)); ++ FILL_PTBL(PAGEBASE(pte_ptr), PHYSADDR, PAGESIZE()); ++ pte_val = ULONG(machdep->ptbl + PAGEOFFSET(pte_ptr)); ++ if (verbose) ++ fprintf(fp, " PTE: %016lx => %016lx\n", (ulong)pte_ptr, pte_val); ++ if (!pte_val) ++ goto no_page; ++ ++ if (!(pte_val & _PAGE_PRESENT)) { ++ if (verbose) { ++ fprintf(fp, "\n"); ++ loongarch64_translate_pte((ulong)pte_val, 0, pte_val); ++ } ++ return FALSE; ++ } ++ ++ *paddr = PTOB(pte_val >> _PFN_SHIFT) + PAGEOFFSET(vaddr); ++ ++ if (verbose) { ++ fprintf(fp, " PAGE: %016lx\n\n", PAGEBASE(*paddr)); ++ loongarch64_translate_pte(pte_val, 0, 0); ++ } ++ ++ return TRUE; ++no_page: ++ fprintf(fp, "invalid\n"); ++ return FALSE; ++} ++ ++/* Translates a user virtual address to its physical address. cmd_vtop() sets ++ * the verbose flag so that the pte translation gets displayed; all other ++ * callers quietly accept the translation. ++ */ ++static int ++loongarch64_uvtop(struct task_context *tc, ulong vaddr, physaddr_t *paddr, int verbose) ++{ ++ ulong mm, active_mm; ++ ulong *pgd; ++ ++ if (!tc) ++ error(FATAL, "current context invalid\n"); ++ ++ *paddr = 0; ++ ++ if (is_kernel_thread(tc->task) && IS_KVADDR(vaddr)) { ++ readmem(tc->task + OFFSET(task_struct_active_mm), ++ KVADDR, &active_mm, sizeof(void *), ++ "task active_mm contents", FAULT_ON_ERROR); ++ ++ if (!active_mm) ++ error(FATAL, ++ "no active_mm for this kernel thread\n"); ++ ++ readmem(active_mm + OFFSET(mm_struct_pgd), ++ KVADDR, &pgd, sizeof(long), ++ "mm_struct pgd", FAULT_ON_ERROR); ++ } else { ++ if ((mm = task_mm(tc->task, TRUE))) ++ pgd = ULONG_PTR(tt->mm_struct + OFFSET(mm_struct_pgd)); ++ else ++ readmem(tc->mm_struct + OFFSET(mm_struct_pgd), ++ KVADDR, &pgd, sizeof(long), "mm_struct pgd", ++ FAULT_ON_ERROR); ++ } ++ ++ return loongarch64_pgd_vtop(pgd, vaddr, paddr, verbose);; ++} ++ ++/* Translates a user virtual address to its physical address. cmd_vtop() sets ++ * the verbose flag so that the pte translation gets displayed; all other ++ * callers quietly accept the translation. ++ */ ++static int ++loongarch64_kvtop(struct task_context *tc, ulong kvaddr, physaddr_t *paddr, int verbose) ++{ ++ if (!IS_KVADDR(kvaddr)) ++ return FALSE; ++ ++ if (!verbose) { ++ if (IS_XKPRANGE(kvaddr)) { ++ *paddr = VTOP(kvaddr); ++ return TRUE; ++ } ++ } ++ ++ return loongarch64_pgd_vtop((ulong *)vt->kernel_pgd[0], kvaddr, paddr, ++ verbose); ++} ++ ++/* ++ * Machine dependent command. ++ */ ++static void ++loongarch64_cmd_mach(void) ++{ ++ int c; ++ ++ while ((c = getopt(argcnt, args, "cmo")) != EOF) { ++ switch (c) { ++ case 'c': ++ case 'm': ++ case 'o': ++ option_not_supported(c); ++ break; ++ default: ++ argerrs++; ++ break; ++ } ++ } ++ ++ if (argerrs) ++ cmd_usage(pc->curcmd, SYNOPSIS); ++ ++ loongarch64_display_machine_stats(); ++} ++ ++/* ++ * "mach" command output. ++ */ ++static void ++loongarch64_display_machine_stats(void) ++{ ++ struct new_utsname *uts; ++ char buf[BUFSIZE]; ++ ulong mhz; ++ ++ uts = &kt->utsname; ++ ++ fprintf(fp, " MACHINE TYPE: %s\n", uts->machine); ++ fprintf(fp, " MEMORY SIZE: %s\n", get_memory_size(buf)); ++ fprintf(fp, " CPUS: %d\n", get_cpus_to_display()); ++ fprintf(fp, " PROCESSOR SPEED: "); ++ if ((mhz = machdep->processor_speed())) ++ fprintf(fp, "%ld Mhz\n", mhz); ++ else ++ fprintf(fp, "(unknown)\n"); ++ fprintf(fp, " HZ: %d\n", machdep->hz); ++ fprintf(fp, " PAGE SIZE: %d\n", PAGESIZE()); ++ fprintf(fp, " KERNEL STACK SIZE: %ld\n", STACKSIZE()); ++ ++} ++ ++/* ++ * Unroll a kernel stack. ++ */ ++static void ++loongarch64_back_trace_cmd(struct bt_info *bt) ++{ ++ struct loongarch64_unwind_frame current, previous; ++ struct loongarch64_pt_regs *regs; ++ char pt_regs[SIZE(pt_regs)]; ++ int level = 0; ++ int invalid_ok = 1; ++ ++ if (bt->flags & BT_REGS_NOT_FOUND) ++ return; ++ ++ previous.sp = previous.pc = previous.ra = 0; ++ ++ current.pc = bt->instptr; ++ current.sp = bt->stkptr; ++ current.ra = 0; ++ ++ if (!INSTACK(current.sp, bt)) ++ return; ++ ++ if (bt->machdep) { ++ regs = (struct loongarch64_pt_regs *)bt->machdep; ++ previous.pc = current.ra = regs->regs[LOONGARCH64_EF_RA]; ++ } ++ ++ while (current.sp <= bt->stacktop - 32 - SIZE(pt_regs)) { ++ struct syment *symbol = NULL; ++ ulong offset; ++ ++ if (CRASHDEBUG(8)) ++ fprintf(fp, "level %d pc %#lx ra %#lx sp %lx\n", ++ level, current.pc, current.ra, current.sp); ++ ++ if (!IS_KVADDR(current.pc) && !invalid_ok) ++ return; ++ ++ symbol = value_search(current.pc, &offset); ++ if (!symbol && !invalid_ok) { ++ error(FATAL, "PC is unknown symbol (%lx)", current.pc); ++ return; ++ } ++ invalid_ok = 0; ++ ++ /* ++ * If we get an address which points to the start of a ++ * function, then it could one of the following: ++ * ++ * - we are dealing with a noreturn function. The last call ++ * from a noreturn function has an ra which points to the ++ * start of the function after it. This is common in the ++ * oops callchain because of die() which is annotated as ++ * noreturn. ++ * ++ * - we have taken an exception at the start of this function. ++ * In this case we already have the RA in current.ra. ++ * ++ * - we are in one of these routines which appear with zero ++ * offset in manually-constructed stack frames: ++ * ++ * * ret_from_exception ++ * * ret_from_irq ++ * * ret_from_fork ++ * * ret_from_kernel_thread ++ */ ++ if (symbol && !STRNEQ(symbol->name, "ret_from") && !offset && ++ !current.ra && current.sp < bt->stacktop - 32 - SIZE(pt_regs)) { ++ if (CRASHDEBUG(8)) ++ fprintf(fp, "zero offset at %s, try previous symbol\n", ++ symbol->name); ++ ++ symbol = value_search(current.pc - 4, &offset); ++ if (!symbol) { ++ error(FATAL, "PC is unknown symbol (%lx)", current.pc); ++ return; ++ } ++ } ++ ++ if (symbol && loongarch64_is_exception_entry(symbol)) { ++ ++ GET_STACK_DATA(current.sp, pt_regs, sizeof(pt_regs)); ++ ++ previous.ra = regs->regs[LOONGARCH64_EF_RA]; ++ previous.sp = regs->regs[LOONGARCH64_EF_SP]; ++ current.ra = regs->csr_epc; ++ ++ if (CRASHDEBUG(8)) ++ fprintf(fp, "exception pc %#lx ra %#lx sp %lx\n", ++ previous.pc, previous.ra, previous.sp); ++ ++ /* The PC causing the exception may have been invalid */ ++ invalid_ok = 1; ++ } else if (symbol) { ++ loongarch64_analyze_function(symbol->value, offset, ¤t, &previous); ++ } else { ++ /* ++ * The current PC is invalid. Assume that the code ++ * jumped through a invalid pointer and that the SP has ++ * not been adjusted. ++ */ ++ previous.sp = current.sp; ++ } ++ ++ if (symbol) ++ loongarch64_dump_backtrace_entry(bt, symbol, ¤t, &previous, level++); ++ ++ current.pc = current.ra; ++ current.sp = previous.sp; ++ current.ra = previous.ra; ++ ++ if (CRASHDEBUG(8)) ++ fprintf(fp, "next %d pc %#lx ra %#lx sp %lx\n", ++ level, current.pc, current.ra, current.sp); ++ ++ previous.sp = previous.pc = previous.ra = 0; ++ } ++} ++ ++static void ++loongarch64_analyze_function(ulong start, ulong offset, ++ struct loongarch64_unwind_frame *current, ++ struct loongarch64_unwind_frame *previous) ++{ ++ ulong i, reg; ++ ulong rapos = 0; ++ ulong spadjust = 0; ++ uint32_t *funcbuf, *ip; ++ ++ if (CRASHDEBUG(8)) ++ fprintf(fp, "%s: start %#lx offset %#lx\n", ++ __func__, start, offset); ++ ++ if (!offset) { ++ previous->sp = current->sp; ++ return; ++ } ++ ++ ip = funcbuf = (uint32_t *)GETBUF(offset); ++ if (!readmem(start, KVADDR, funcbuf, offset, ++ "loongarch64_analyze_function", RETURN_ON_ERROR)) { ++ FREEBUF(funcbuf); ++ error(WARNING, "Cannot read function at %16lx\n", start); ++ return; ++ } ++ ++ for (i = 0; i < offset; i += 4) { ++ ulong insn = *ip & 0xffffffff; ++ ulong si12 = (insn >> 10) & 0xfff; /* bit[10:21] */ ++ ++ if (CRASHDEBUG(8)) ++ fprintf(fp, "insn @ %#lx = %#lx\n", start + i, insn); ++ ++ if ((insn & 0xffc003ff) == 0x02800063 || /* addi.w sp,sp,si12 */ ++ (insn & 0xffc003ff) == 0x02c00063) { /* addi.d sp,sp,si12 */ ++ if (!(si12 & 0x800)) /* si12 < 0 */ ++ break; ++ spadjust += 0x1000 - si12; ++ if (CRASHDEBUG(8)) ++ fprintf(fp, "si12 =%lu ,spadjust = %lu\n", si12, spadjust); ++ } else if ((insn & 0xffc003ff) == 0x29800061 || /* st.w ra,sp,si12 */ ++ (insn & 0xffc003ff) == 0x29c00061) { /* st.d ra,sp,si12 */ ++ rapos = current->sp + si12; ++ if (CRASHDEBUG(8)) ++ fprintf(fp, "rapos %lx\n", rapos); ++ break; ++ } ++ ++ ip++; ++ } ++ ++ FREEBUF(funcbuf); ++ ++ previous->sp = current->sp + spadjust; ++ ++ if (rapos && !readmem(rapos, KVADDR, ¤t->ra, ++ sizeof(current->ra), "RA from stack", ++ RETURN_ON_ERROR)) { ++ error(FATAL, "Cannot read RA from stack %lx", rapos); ++ return; ++ } ++} ++ ++static void ++loongarch64_dump_backtrace_entry(struct bt_info *bt, struct syment *sym, ++ struct loongarch64_unwind_frame *current, ++ struct loongarch64_unwind_frame *previous, int level) ++{ ++ const char *name = sym ? sym->name : "(invalid)"; ++ struct load_module *lm; ++ char *name_plus_offset = NULL; ++ struct syment *symp; ++ ulong symbol_offset; ++ char buf[BUFSIZE]; ++ char pt_regs[SIZE(pt_regs)]; ++ ++ if (bt->flags & BT_SYMBOL_OFFSET) { ++ symp = value_search(current->pc, &symbol_offset); ++ ++ if (symp && symbol_offset) ++ name_plus_offset = ++ value_to_symstr(current->pc, buf, bt->radix); ++ } ++ ++ fprintf(fp, "%s#%d [%016lx] %s at %016lx", level < 10 ? " " : "", level, ++ current->sp, name_plus_offset ? name_plus_offset : name, ++ current->pc); ++ ++ if (module_symbol(current->pc, NULL, &lm, NULL, 0)) ++ fprintf(fp, " [%s]", lm->mod_name); ++ ++ fprintf(fp, "\n"); ++ ++ /* ++ * 'bt -l', get a line number associated with a current pc address. ++ */ ++ if (bt->flags & BT_LINE_NUMBERS) { ++ get_line_number(current->pc, buf, FALSE); ++ if (strlen(buf)) ++ fprintf(fp, " %s\n", buf); ++ } ++ ++ if (sym && loongarch64_is_exception_entry(sym)) { ++ GET_STACK_DATA(current->sp, &pt_regs, SIZE(pt_regs)); ++ loongarch64_dump_exception_stack(bt, pt_regs); ++ } ++ ++ /* bt -f */ ++ if (bt->flags & BT_FULL) { ++ fprintf(fp, " " ++ "[PC: %016lx RA: %016lx SP: %016lx SIZE: %ld]\n", ++ current->pc, current->ra, current->sp, ++ previous->sp - current->sp); ++ loongarch64_display_full_frame(bt, current, previous); ++ } ++} ++ ++static void ++loongarch64_dump_exception_stack(struct bt_info *bt, char *pt_regs) ++{ ++ struct loongarch64_pt_regs *regs; ++ int i; ++ char buf[BUFSIZE]; ++ ++ for (i = 0; i < 32; i += 4) { ++ fprintf(fp, " $%2d : %016lx %016lx %016lx %016lx\n", ++ i, regs->regs[i], regs->regs[i+1], ++ regs->regs[i+2], regs->regs[i+3]); ++ } ++ ++ value_to_symstr(regs->csr_epc, buf, 16); ++ fprintf(fp, " epc : %016lx %s\n", regs->csr_epc, buf); ++ ++ value_to_symstr(regs->regs[LOONGARCH64_EF_RA], buf, 16); ++ fprintf(fp, " ra : %016lx %s\n", regs->regs[LOONGARCH64_EF_RA], buf); ++ ++ fprintf(fp, " CSR crmd : %016lx\n", regs->csr_crmd); ++ fprintf(fp, " CSR prmd : %016lx\n", regs->csr_prmd); ++ fprintf(fp, " CSR ecfg : %016lx\n", regs->csr_ecfg); ++ fprintf(fp, " CSR estat: %016lx\n", regs->csr_estat); ++ fprintf(fp, " CSR euen : %016lx\n", regs->csr_euen); ++ ++ fprintf(fp, " BadVA : %016lx\n", regs->csr_badvaddr); ++} ++ ++static int ++loongarch64_is_exception_entry(struct syment *sym) ++{ ++ return STREQ(sym->name, "ret_from_exception") || ++ STREQ(sym->name, "ret_from_irq") || ++ STREQ(sym->name, "work_resched") || ++ STREQ(sym->name, "handle_sys"); ++} ++ ++/* ++ * 'bt -f' commend output ++ * Display all stack data contained in a frame ++ */ ++static void ++loongarch64_display_full_frame(struct bt_info *bt, struct loongarch64_unwind_frame *current, ++ struct loongarch64_unwind_frame *previous) ++{ ++ int i, u_idx; ++ ulong *up; ++ ulong words, addr; ++ char buf[BUFSIZE]; ++ ++ if (previous->sp < current->sp) ++ return; ++ ++ if (!(INSTACK(previous->sp, bt) && INSTACK(current->sp, bt))) ++ return; ++ ++ words = (previous->sp - current->sp) / sizeof(ulong) + 1; ++ addr = current->sp; ++ u_idx = (current->sp - bt->stackbase) / sizeof(ulong); ++ ++ for (i = 0; i < words; i++, u_idx++) { ++ if (!(i & 1)) ++ fprintf(fp, "%s %lx: ", i ? "\n" : "", addr); ++ ++ up = (ulong *)(&bt->stackbuf[u_idx*sizeof(ulong)]); ++ fprintf(fp, "%s ", format_stack_entry(bt, buf, *up, 0)); ++ addr += sizeof(ulong); ++ } ++ fprintf(fp, "\n"); ++} ++ ++static void ++loongarch64_stackframe_init(void) ++{ ++ long task_struct_thread = MEMBER_OFFSET("task_struct", "thread"); ++ long thread_reg03_sp = MEMBER_OFFSET("thread_struct", "reg03"); ++ long thread_reg01_ra = MEMBER_OFFSET("thread_struct", "reg01"); ++ ++ if ((task_struct_thread == INVALID_OFFSET) || ++ (thread_reg03_sp == INVALID_OFFSET) || ++ (thread_reg01_ra == INVALID_OFFSET)) { ++ error(FATAL, ++ "cannot determine thread_struct offsets\n"); ++ return; ++ } ++ ++ ASSIGN_OFFSET(task_struct_thread_reg03) = ++ task_struct_thread + thread_reg03_sp; ++ ASSIGN_OFFSET(task_struct_thread_reg01) = ++ task_struct_thread + thread_reg01_ra; ++ ++ MEMBER_OFFSET_INIT(elf_prstatus_pr_reg, "elf_prstatus", "pr_reg"); ++ STRUCT_SIZE_INIT(note_buf, "note_buf_t"); ++} ++ ++/* ++ * Get a stack frame combination of pc and ra from the most relevant spot. ++ */ ++static void ++loongarch64_get_stack_frame(struct bt_info *bt, ulong *pcp, ulong *spp) ++{ ++ ulong ksp, nip; ++ int ret = 0; ++ ++ nip = ksp = 0; ++ bt->machdep = NULL; ++ ++ if (DUMPFILE() && is_task_active(bt->task)) { ++ ret = loongarch64_get_dumpfile_stack_frame(bt, &nip, &ksp); ++ } ++ else { ++ ret = loongarch64_get_frame(bt, &nip, &ksp); ++ } ++ ++ if (!ret) ++ error(WARNING, "cannot determine starting stack frame for task %lx\n", ++ bt->task); ++ ++ if (pcp) ++ *pcp = nip; ++ if (spp) ++ *spp = ksp; ++} ++ ++/* ++ * Get the starting point for the active cpu in a diskdump. ++ */ ++static int ++loongarch64_get_dumpfile_stack_frame(struct bt_info *bt, ulong *nip, ulong *ksp) ++{ ++ const struct machine_specific *ms = machdep->machspec; ++ struct loongarch64_pt_regs *regs; ++ ulong epc, sp; ++ ++ if (!ms->crash_task_regs) { ++ bt->flags |= BT_REGS_NOT_FOUND; ++ return FALSE; ++ } ++ ++ /* ++ * We got registers for panic task from crash_notes. Just return them. ++ */ ++ regs = &ms->crash_task_regs[bt->tc->processor]; ++ epc = regs->regs[LOONGARCH64_EF_CSR_EPC]; ++ sp = regs->regs[LOONGARCH64_EF_SP]; ++ ++ if (!epc && !sp) { ++ bt->flags |= BT_REGS_NOT_FOUND; ++ return FALSE; ++ } ++ ++ if (nip) ++ *nip = epc; ++ if (ksp) ++ *ksp = sp; ++ ++ bt->machdep = regs; ++ ++ return TRUE; ++} ++ ++/* ++ * Do the work for loongarch64_get_stack_frame() for non-active tasks. ++ * Get SP and PC values for idle tasks. ++ */ ++static int ++loongarch64_get_frame(struct bt_info *bt, ulong *pcp, ulong *spp) ++{ ++ if (!bt->tc || !(tt->flags & THREAD_INFO)) ++ return FALSE; ++ ++ if (!readmem(bt->task + OFFSET(task_struct_thread_reg01), ++ KVADDR, pcp, sizeof(*pcp), ++ "thread_struct.regs01", ++ RETURN_ON_ERROR)) { ++ return FALSE; ++ } ++ ++ if (!readmem(bt->task + OFFSET(task_struct_thread_reg03), ++ KVADDR, spp, sizeof(*spp), ++ "thread_struct.regs03", ++ RETURN_ON_ERROR)) { ++ return FALSE; ++ } ++ ++ return TRUE; ++} ++ ++static int ++loongarch64_init_active_task_regs(void) ++{ ++ int retval; ++ ++ retval = loongarch64_get_crash_notes(); ++ if (retval == TRUE) ++ return retval; ++ ++ return loongarch64_get_elf_notes(); ++} ++ ++/* ++ * Retrieve task registers for the time of the crash. ++ */ ++static int ++loongarch64_get_crash_notes(void) ++{ ++ struct machine_specific *ms = machdep->machspec; ++ ulong crash_notes; ++ Elf64_Nhdr *note; ++ ulong offset; ++ char *buf, *p; ++ ulong *notes_ptrs; ++ ulong i; ++ ++ /* ++ * crash_notes contains per cpu memory for storing cpu states ++ * in case of system crash. ++ */ ++ if (!symbol_exists("crash_notes")) ++ return FALSE; ++ ++ crash_notes = symbol_value("crash_notes"); ++ ++ notes_ptrs = (ulong *)GETBUF(kt->cpus*sizeof(notes_ptrs[0])); ++ ++ /* ++ * Read crash_notes for the first CPU. crash_notes are in standard ELF ++ * note format. ++ */ ++ if (!readmem(crash_notes, KVADDR, ¬es_ptrs[kt->cpus-1], ++ sizeof(notes_ptrs[kt->cpus-1]), "crash_notes", ++ RETURN_ON_ERROR)) { ++ error(WARNING, "cannot read crash_notes\n"); ++ FREEBUF(notes_ptrs); ++ return FALSE; ++ } ++ ++ if (symbol_exists("__per_cpu_offset")) { ++ ++ /* ++ * Add __per_cpu_offset for each cpu to form the pointer to the notes ++ */ ++ for (i = 0; i < kt->cpus; i++) ++ notes_ptrs[i] = notes_ptrs[kt->cpus-1] + kt->__per_cpu_offset[i]; ++ } ++ ++ buf = GETBUF(SIZE(note_buf)); ++ ++ if (!(panic_task_regs = calloc((size_t)kt->cpus, sizeof(*panic_task_regs)))) ++ error(FATAL, "cannot calloc panic_task_regs space\n"); ++ ++ for (i = 0; i < kt->cpus; i++) { ++ ++ if (!readmem(notes_ptrs[i], KVADDR, buf, SIZE(note_buf), "note_buf_t", ++ RETURN_ON_ERROR)) { ++ error(WARNING, ++ "cannot find NT_PRSTATUS note for cpu: %d\n", i); ++ goto fail; ++ } ++ ++ /* ++ * Do some sanity checks for this note before reading registers from it. ++ */ ++ note = (Elf64_Nhdr *)buf; ++ p = buf + sizeof(Elf64_Nhdr); ++ ++ /* ++ * dumpfiles created with qemu won't have crash_notes, but there will ++ * be elf notes; dumpfiles created by kdump do not create notes for ++ * offline cpus. ++ */ ++ if (note->n_namesz == 0 && (DISKDUMP_DUMPFILE() || KDUMP_DUMPFILE())) { ++ if (DISKDUMP_DUMPFILE()) ++ note = diskdump_get_prstatus_percpu(i); ++ else if (KDUMP_DUMPFILE()) ++ note = netdump_get_prstatus_percpu(i); ++ if (note) { ++ /* ++ * SIZE(note_buf) accounts for a "final note", which is a ++ * trailing empty elf note header. ++ */ ++ long notesz = SIZE(note_buf) - sizeof(Elf64_Nhdr); ++ ++ if (sizeof(Elf64_Nhdr) + roundup(note->n_namesz, 4) + ++ note->n_descsz == notesz) ++ BCOPY((char *)note, buf, notesz); ++ } else { ++ error(WARNING, ++ "cannot find NT_PRSTATUS note for cpu: %d\n", i); ++ continue; ++ } ++ } ++ ++ /* ++ * Check the sanity of NT_PRSTATUS note only for each online cpu. ++ */ ++ if (note->n_type != NT_PRSTATUS) { ++ error(WARNING, "invalid NT_PRSTATUS note (n_type != NT_PRSTATUS)\n"); ++ goto fail; ++ } ++ if (!STRNEQ(p, "CORE")) { ++ error(WARNING, "invalid NT_PRSTATUS note (name != \"CORE\"\n"); ++ goto fail; ++ } ++ ++ /* ++ * Find correct location of note data. This contains elf_prstatus ++ * structure which has registers etc. for the crashed task. ++ */ ++ offset = sizeof(Elf64_Nhdr); ++ offset = roundup(offset + note->n_namesz, 4); ++ p = buf + offset; /* start of elf_prstatus */ ++ ++ BCOPY(p + OFFSET(elf_prstatus_pr_reg), &panic_task_regs[i], ++ sizeof(panic_task_regs[i])); ++ } ++ ++ /* ++ * And finally we have the registers for the crashed task. This is ++ * used later on when dumping backtrace. ++ */ ++ ms->crash_task_regs = panic_task_regs; ++ ++ FREEBUF(buf); ++ FREEBUF(notes_ptrs); ++ return TRUE; ++ ++fail: ++ FREEBUF(buf); ++ FREEBUF(notes_ptrs); ++ free(panic_task_regs); ++ return FALSE; ++} ++ ++static int ++loongarch64_get_elf_notes(void) ++{ ++ struct machine_specific *ms = machdep->machspec; ++ int i; ++ ++ if (!DISKDUMP_DUMPFILE() && !KDUMP_DUMPFILE()) ++ return FALSE; ++ ++ panic_task_regs = calloc(kt->cpus, sizeof(*panic_task_regs)); ++ if (!panic_task_regs) ++ error(FATAL, "cannot calloc panic_task_regs space\n"); ++ ++ for (i = 0; i < kt->cpus; i++) { ++ Elf64_Nhdr *note = NULL; ++ size_t len; ++ ++ if (DISKDUMP_DUMPFILE()) ++ note = diskdump_get_prstatus_percpu(i); ++ else if (KDUMP_DUMPFILE()) ++ note = netdump_get_prstatus_percpu(i); ++ ++ if (!note) { ++ error(WARNING, ++ "cannot find NT_PRSTATUS note for cpu: %d\n", i); ++ continue; ++ } ++ ++ len = sizeof(Elf64_Nhdr); ++ len = roundup(len + note->n_namesz, 4); ++ ++ BCOPY((char *)note + len + OFFSET(elf_prstatus_pr_reg), ++ &panic_task_regs[i], sizeof(panic_task_regs[i])); ++ } ++ ++ ms->crash_task_regs = panic_task_regs; ++ ++ return TRUE; ++} ++ ++/* ++ * Accept or reject a symbol from the kernel namelist. ++ */ ++static int ++loongarch64_verify_symbol(const char *name, ulong value, char type) ++{ ++ if (CRASHDEBUG(8) && name && strlen(name)) ++ fprintf(fp, "%08lx %s\n", value, name); ++ ++ if (STREQ(name, "_text") || STREQ(name, "_stext")) ++ machdep->flags |= KSYMS_START; ++ ++ return (name && strlen(name) && (machdep->flags & KSYMS_START) && ++ !STRNEQ(name, "__func__.") && !STRNEQ(name, "__crc_")); ++} ++ ++/* ++ * Override smp_num_cpus if possible and necessary. ++ */ ++static int ++loongarch64_get_smp_cpus(void) ++{ ++ return (get_cpus_online() > 0) ? get_cpus_online() : kt->cpus; ++} ++ ++static ulong ++loongarch64_get_page_size(void) ++{ ++ return memory_page_size(); ++} ++ ++/* ++ * Determine where vmalloc'd memory starts. ++ */ ++static ulong ++loongarch64_vmalloc_start(void) ++{ ++ return first_vmalloc_address(); ++} ++ ++/* ++ * Calculate and return the speed of the processor. ++ */ ++static ulong ++loongarch64_processor_speed(void) ++{ ++ unsigned long cpu_hz = 0; ++ ++ if (machdep->mhz) ++ return (machdep->mhz); ++ ++ if (symbol_exists("cpu_clock_freq")) { ++ get_symbol_data("cpu_clock_freq", sizeof(int), &cpu_hz); ++ if (cpu_hz) ++ return(machdep->mhz = cpu_hz/1000000); ++ } ++ ++ return 0; ++} ++ ++/* ++ * Checks whether given task is valid task address. ++ */ ++static int ++loongarch64_is_task_addr(ulong task) ++{ ++ if (tt->flags & THREAD_INFO) ++ return IS_KVADDR(task); ++ ++ return (IS_KVADDR(task) && ALIGNED_STACK_OFFSET(task) == 0); ++} ++ ++/* ++ * 'help -m/M' command output ++ */ ++void ++loongarch64_dump_machdep_table(ulong arg) ++{ ++ int others = 0; ++ ++ fprintf(fp, " flags: %lx (", machdep->flags); ++ if (machdep->flags & KSYMS_START) ++ fprintf(fp, "%sKSYMS_START", others++ ? "|" : ""); ++ fprintf(fp, ")\n"); ++ ++ fprintf(fp, " kvbase: %lx\n", machdep->kvbase); ++ fprintf(fp, " identity_map_base: %lx\n", machdep->identity_map_base); ++ fprintf(fp, " pagesize: %d\n", machdep->pagesize); ++ fprintf(fp, " pageshift: %d\n", machdep->pageshift); ++ fprintf(fp, " pagemask: %llx\n", machdep->pagemask); ++ fprintf(fp, " pageoffset: %lx\n", machdep->pageoffset); ++ fprintf(fp, " pgdir_shift: %d\n", PGDIR_SHIFT); ++ fprintf(fp, " ptrs_per_pgd: %lu\n", PTRS_PER_PGD); ++ fprintf(fp, " ptrs_per_pte: %ld\n", PTRS_PER_PTE); ++ fprintf(fp, " stacksize: %ld\n", machdep->stacksize); ++ fprintf(fp, " hz: %d\n", machdep->hz); ++ fprintf(fp, " memsize: %ld (0x%lx)\n", ++ machdep->memsize, machdep->memsize); ++ fprintf(fp, " bits: %d\n", machdep->bits); ++ fprintf(fp, " back_trace: loongarch64_back_trace_cmd()\n"); ++ fprintf(fp, " processor_speed: loongarch64_processor_speed()\n"); ++ fprintf(fp, " uvtop: loongarch64_uvtop()\n"); ++ fprintf(fp, " kvtop: loongarch64_kvtop()\n"); ++ fprintf(fp, " get_stack_frame: loongarch64_get_stack_frame()\n"); ++ fprintf(fp, " get_stackbase: generic_get_stackbase()\n"); ++ fprintf(fp, " get_stacktop: generic_get_stacktop()\n"); ++ fprintf(fp, " translate_pte: loongarch64_translate_pte()\n"); ++ fprintf(fp, " memory_size: generic_memory_size()\n"); ++ fprintf(fp, " vmalloc_start: loongarch64_vmalloc_start()\n"); ++ fprintf(fp, " is_task_addr: loongarch64_is_task_addr()\n"); ++ fprintf(fp, " verify_symbol: loongarch64_verify_symbol()\n"); ++ fprintf(fp, " dis_filter: generic_dis_filter()\n"); ++ fprintf(fp, " dump_irq: generic_dump_irq()\n"); ++ fprintf(fp, " show_interrupts: generic_show_interrupts()\n"); ++ fprintf(fp, " get_irq_affinity: generic_get_irq_affinity()\n"); ++ fprintf(fp, " cmd_mach: loongarch64_cmd_mach()\n"); ++ fprintf(fp, " get_smp_cpus: loongarch64_get_smp_cpus()\n"); ++ fprintf(fp, " is_kvaddr: generic_is_kvaddr()\n"); ++ fprintf(fp, " is_uvaddr: generic_is_uvaddr()\n"); ++ fprintf(fp, " verify_paddr: generic_verify_paddr()\n"); ++ fprintf(fp, " init_kernel_pgd: NULL\n"); ++ fprintf(fp, " value_to_symbol: generic_machdep_value_to_symbol()\n"); ++ fprintf(fp, " line_number_hooks: NULL\n"); ++ fprintf(fp, " last_pgd_read: %lx\n", machdep->last_pgd_read); ++ fprintf(fp, " last_pmd_read: %lx\n", machdep->last_pmd_read); ++ fprintf(fp, " last_ptbl_read: %lx\n", machdep->last_ptbl_read); ++ fprintf(fp, " pgd: %lx\n", (ulong)machdep->pgd); ++ fprintf(fp, " pmd: %lx\n", (ulong)machdep->pmd); ++ fprintf(fp, " ptbl: %lx\n", (ulong)machdep->ptbl); ++ fprintf(fp, " section_size_bits: %ld\n", machdep->section_size_bits); ++ fprintf(fp, " max_physmem_bits: %ld\n", machdep->max_physmem_bits); ++ fprintf(fp, " sections_per_root: %ld\n", machdep->sections_per_root); ++ fprintf(fp, " machspec: %lx\n", (ulong)machdep->machspec); ++} ++ ++static void ++pt_level_alloc(char **lvl, char *name) ++{ ++ size_t sz = PAGESIZE(); ++ void *pointer = malloc(sz); ++ ++ if (!pointer) ++ error(FATAL, name); ++ *lvl = pointer; ++} ++ ++void ++loongarch64_init(int when) ++{ ++ switch (when) { ++ case SETUP_ENV: ++ machdep->process_elf_notes = process_elf64_notes; ++ break; ++ ++ case PRE_SYMTAB: ++ machdep->verify_symbol = loongarch64_verify_symbol; ++ machdep->machspec = &loongarch64_machine_specific; ++ if (pc->flags & KERNEL_DEBUG_QUERY) ++ return; ++ machdep->last_pgd_read = 0; ++ machdep->last_pmd_read = 0; ++ machdep->last_ptbl_read = 0; ++ machdep->verify_paddr = generic_verify_paddr; ++ machdep->ptrs_per_pgd = PTRS_PER_PGD; ++ break; ++ ++ case PRE_GDB: ++ machdep->pagesize = loongarch64_get_page_size(); ++ machdep->pageshift = ffs(machdep->pagesize) - 1; ++ machdep->pageoffset = machdep->pagesize - 1; ++ machdep->pagemask = ~((ulonglong)machdep->pageoffset); ++ if (machdep->pagesize >= 16384) ++ machdep->stacksize = machdep->pagesize; ++ else ++ machdep->stacksize = machdep->pagesize * 2; ++ ++ pt_level_alloc(&machdep->pgd, "cannot malloc pgd space."); ++ pt_level_alloc(&machdep->pmd, "cannot malloc pmd space."); ++ pt_level_alloc(&machdep->ptbl, "cannot malloc ptbl space."); ++ machdep->kvbase = 0x8000000000000000lu; ++ machdep->identity_map_base = machdep->kvbase; ++ machdep->is_kvaddr = generic_is_kvaddr; ++ machdep->is_uvaddr = generic_is_uvaddr; ++ machdep->uvtop = loongarch64_uvtop; ++ machdep->kvtop = loongarch64_kvtop; ++ machdep->cmd_mach = loongarch64_cmd_mach; ++ machdep->back_trace = loongarch64_back_trace_cmd; ++ machdep->get_stack_frame = loongarch64_get_stack_frame; ++ machdep->vmalloc_start = loongarch64_vmalloc_start; ++ machdep->processor_speed = loongarch64_processor_speed; ++ machdep->get_stackbase = generic_get_stackbase; ++ machdep->get_stacktop = generic_get_stacktop; ++ machdep->translate_pte = loongarch64_translate_pte; ++ machdep->memory_size = generic_memory_size; ++ machdep->is_task_addr = loongarch64_is_task_addr; ++ machdep->get_smp_cpus = loongarch64_get_smp_cpus; ++ machdep->dis_filter = generic_dis_filter; ++ machdep->dump_irq = generic_dump_irq; ++ machdep->show_interrupts = generic_show_interrupts; ++ machdep->get_irq_affinity = generic_get_irq_affinity; ++ machdep->value_to_symbol = generic_machdep_value_to_symbol; ++ machdep->init_kernel_pgd = NULL; ++ break; ++ ++ case POST_GDB: ++ machdep->section_size_bits = _SECTION_SIZE_BITS; ++ machdep->max_physmem_bits = _MAX_PHYSMEM_BITS; ++ ++ if (symbol_exists("irq_desc")) ++ ARRAY_LENGTH_INIT(machdep->nr_irqs, irq_desc, ++ "irq_desc", NULL, 0); ++ else if (kernel_symbol_exists("nr_irqs")) ++ get_symbol_data("nr_irqs", sizeof(unsigned int), ++ &machdep->nr_irqs); ++ ++ loongarch64_stackframe_init(); ++ ++ if (!machdep->hz) ++ machdep->hz = 250; ++ break; ++ ++ case POST_VM: ++ /* ++ * crash_notes contains machine specific information about the ++ * crash. In particular, it contains CPU registers at the time ++ * of the crash. We need this information to extract correct ++ * backtraces from the panic task. ++ */ ++ if (!ACTIVE() && !loongarch64_init_active_task_regs()) ++ error(WARNING,"cannot retrieve registers for active task%s\n\n", ++ kt->cpus > 1 ? "s" : ""); ++ break; ++ } ++} ++ ++void ++loongarch64_display_regs_from_elf_notes(int cpu, FILE *ofp) ++{ ++ const struct machine_specific *ms = machdep->machspec; ++ struct loongarch64_pt_regs *regs; ++ ++ if (!ms->crash_task_regs) { ++ error(INFO, "registers not collected for cpu %d\n", cpu); ++ return; ++ } ++ ++ regs = &ms->crash_task_regs[cpu]; ++ if (!regs->regs[LOONGARCH64_EF_SP] && !regs->regs[LOONGARCH64_EF_CSR_EPC]) { ++ error(INFO, "registers not collected for cpu %d\n", cpu); ++ return; ++ } ++ ++ fprintf(ofp, ++ " R0: %016lx R1: %016lx R2: %016lx\n" ++ " R3: %016lx R4: %016lx R5: %016lx\n" ++ " R6: %016lx R7: %016lx R8: %016lx\n" ++ " R9: %016lx R10: %016lx R11: %016lx\n" ++ " R12: %016lx R13: %016lx R14: %016lx\n" ++ " R15: %016lx R16: %016lx R17: %016lx\n" ++ " R18: %016lx R19: %016lx R20: %016lx\n" ++ " R21: %016lx R22: %016lx R23: %016lx\n" ++ " R24: %016lx R25: %016lx R26: %016lx\n" ++ " R27: %016lx R28: %016lx R29: %016lx\n" ++ " R30: %016lx R31: %016lx\n" ++ " CSR epc : %016lx CSR badv: %016lx\n" ++ " CSR crmd: %08lx CSR prmd: %08lx\n" ++ " CSR ecfg: %08lx CSR estat: %08lx\n" ++ " CSR eneu: %08lx", ++ regs->regs[LOONGARCH64_EF_R0], ++ regs->regs[LOONGARCH64_EF_R0 + 1], ++ regs->regs[LOONGARCH64_EF_R0 + 2], ++ regs->regs[LOONGARCH64_EF_R0 + 3], ++ regs->regs[LOONGARCH64_EF_R0 + 4], ++ regs->regs[LOONGARCH64_EF_R0 + 5], ++ regs->regs[LOONGARCH64_EF_R0 + 6], ++ regs->regs[LOONGARCH64_EF_R0 + 7], ++ regs->regs[LOONGARCH64_EF_R0 + 8], ++ regs->regs[LOONGARCH64_EF_R0 + 9], ++ regs->regs[LOONGARCH64_EF_R0 + 10], ++ regs->regs[LOONGARCH64_EF_R0 + 11], ++ regs->regs[LOONGARCH64_EF_R0 + 12], ++ regs->regs[LOONGARCH64_EF_R0 + 13], ++ regs->regs[LOONGARCH64_EF_R0 + 14], ++ regs->regs[LOONGARCH64_EF_R0 + 15], ++ regs->regs[LOONGARCH64_EF_R0 + 16], ++ regs->regs[LOONGARCH64_EF_R0 + 17], ++ regs->regs[LOONGARCH64_EF_R0 + 18], ++ regs->regs[LOONGARCH64_EF_R0 + 19], ++ regs->regs[LOONGARCH64_EF_R0 + 20], ++ regs->regs[LOONGARCH64_EF_R0 + 21], ++ regs->regs[LOONGARCH64_EF_R0 + 22], ++ regs->regs[LOONGARCH64_EF_R0 + 23], ++ regs->regs[LOONGARCH64_EF_R0 + 24], ++ regs->regs[LOONGARCH64_EF_R0 + 25], ++ regs->regs[LOONGARCH64_EF_R0 + 26], ++ regs->regs[LOONGARCH64_EF_R0 + 27], ++ regs->regs[LOONGARCH64_EF_R0 + 28], ++ regs->regs[LOONGARCH64_EF_R0 + 29], ++ regs->regs[LOONGARCH64_EF_R0 + 30], ++ regs->regs[LOONGARCH64_EF_R0 + 31], ++ regs->regs[LOONGARCH64_EF_CSR_EPC], ++ regs->regs[LOONGARCH64_EF_CSR_BADVADDR], ++ regs->regs[LOONGARCH64_EF_CSR_CRMD], ++ regs->regs[LOONGARCH64_EF_CSR_PRMD], ++ regs->regs[LOONGARCH64_EF_CSR_ECFG], ++ regs->regs[LOONGARCH64_EF_CSR_ESTAT], ++ regs->regs[LOONGARCH64_EF_CSR_EUEN]); ++} ++ ++#else /* !LOONGARCH64 */ ++ ++#include "defs.h" ++ ++void ++loongarch64_display_regs_from_elf_notes(int cpu, FILE *ofp) ++{ ++ return; ++} ++ ++#endif /* !LOONGARCH64 */ +diff --git a/netdump.c b/netdump.c +index ff273b4..f8ce939 100644 +--- a/netdump.c ++++ b/netdump.c +@@ -42,6 +42,7 @@ static void get_netdump_regs_ppc64(struct bt_info *, ulong *, ulong *); + static void get_netdump_regs_arm(struct bt_info *, ulong *, ulong *); + static void get_netdump_regs_arm64(struct bt_info *, ulong *, ulong *); + static void get_netdump_regs_mips(struct bt_info *, ulong *, ulong *); ++static void get_netdump_regs_loongarch64(struct bt_info *, ulong *, ulong *); + static void check_dumpfile_size(char *); + static int proc_kcore_init_32(FILE *, int); + static int proc_kcore_init_64(FILE *, int); +@@ -300,6 +301,12 @@ is_netdump(char *file, ulong source_query) + goto bailout; + break; + ++ case EM_LOONGARCH: ++ if (machine_type_mismatch(file, "LOONGARCH64", NULL, ++ source_query)) ++ goto bailout; ++ break; ++ + default: + if (machine_type_mismatch(file, "(unknown)", NULL, + source_query)) +@@ -1482,6 +1489,9 @@ dump_Elf32_Ehdr(Elf32_Ehdr *elf) + case EM_MIPS: + netdump_print("(EM_MIPS)\n"); + break; ++ case EM_LOONGARCH: ++ netdump_print("(EM_LOONGARCH)\n"); ++ break; + default: + netdump_print("(unsupported)\n"); + break; +@@ -1644,6 +1654,9 @@ dump_Elf64_Ehdr(Elf64_Ehdr *elf) + case EM_AARCH64: + netdump_print("(EM_AARCH64)\n"); + break; ++ case EM_LOONGARCH: ++ netdump_print("(EM_LOONGARCH)\n"); ++ break; + default: + netdump_print("(unsupported)\n"); + break; +@@ -2669,6 +2682,10 @@ get_netdump_regs(struct bt_info *bt, ulong *eip, ulong *esp) + return get_netdump_regs_mips(bt, eip, esp); + break; + ++ case EM_LOONGARCH: ++ return get_netdump_regs_loongarch64(bt, eip, esp); ++ break; ++ + default: + error(FATAL, + "support for ELF machine type %d not available\n", +@@ -2925,6 +2942,8 @@ display_regs_from_elf_notes(int cpu, FILE *ofp) + mips_display_regs_from_elf_notes(cpu, ofp); + } else if (machine_type("MIPS64")) { + mips64_display_regs_from_elf_notes(cpu, ofp); ++ } else if (machine_type("LOONGARCH64")) { ++ loongarch64_display_regs_from_elf_notes(cpu, ofp); + } + } + +@@ -2935,7 +2954,8 @@ dump_registers_for_elf_dumpfiles(void) + + if (!(machine_type("X86") || machine_type("X86_64") || + machine_type("ARM64") || machine_type("PPC64") || +- machine_type("MIPS") || machine_type("MIPS64"))) ++ machine_type("MIPS") || machine_type("MIPS64") || ++ machine_type("LOONGARCH64"))) + error(FATAL, "-r option not supported for this dumpfile\n"); + + if (NETDUMP_DUMPFILE()) { +@@ -3870,6 +3890,12 @@ get_netdump_regs_mips(struct bt_info *bt, ulong *eip, ulong *esp) + machdep->get_stack_frame(bt, eip, esp); + } + ++static void ++get_netdump_regs_loongarch64(struct bt_info *bt, ulong *eip, ulong *esp) ++{ ++ machdep->get_stack_frame(bt, eip, esp); ++} ++ + int + is_partial_netdump(void) + { +diff --git a/ramdump.c b/ramdump.c +index a206fcb..c32d9fd 100644 +--- a/ramdump.c ++++ b/ramdump.c +@@ -188,6 +188,8 @@ char *ramdump_to_elf(void) + e_machine = EM_MIPS; + else if (machine_type("X86_64")) + e_machine = EM_X86_64; ++ else if (machine_type("LOONGARCH64")) ++ e_machine = EM_LOONGARCH; + else + error(FATAL, "ramdump: unsupported machine type: %s\n", + MACHINE_TYPE); +diff --git a/symbols.c b/symbols.c +index bee1faf..5f870a5 100644 +--- a/symbols.c ++++ b/symbols.c +@@ -3694,6 +3694,11 @@ is_kernel(char *file) + goto bailout; + break; + ++ case EM_LOONGARCH: ++ if (machine_type_mismatch(file, "LOONGARCH64", NULL, 0)) ++ goto bailout; ++ break; ++ + default: + if (machine_type_mismatch(file, "(unknown)", NULL, 0)) + goto bailout; +@@ -4002,6 +4007,11 @@ is_shared_object(char *file) + if (machine_type("MIPS64")) + return TRUE; + break; ++ ++ case EM_LOONGARCH: ++ if (machine_type("LOONGARCH64")) ++ return TRUE; ++ break; + } + + if (CRASHDEBUG(1)) +@@ -8818,6 +8828,10 @@ dump_offset_table(char *spec, ulong makestruct) + OFFSET(task_struct_thread_esp)); + fprintf(fp, " task_struct_thread_ksp: %ld\n", + OFFSET(task_struct_thread_ksp)); ++ fprintf(fp, " task_struct_thread_reg01: %ld\n", ++ OFFSET(task_struct_thread_reg01)); ++ fprintf(fp, " task_struct_thread_reg03: %ld\n", ++ OFFSET(task_struct_thread_reg03)); + fprintf(fp, " task_struct_thread_reg29: %ld\n", + OFFSET(task_struct_thread_reg29)); + fprintf(fp, " task_struct_thread_reg31: %ld\n", +-- +2.27.0 + diff --git a/0001-ppc64-update-the-NR_CPUS-to-8192.patch b/0001-ppc64-update-the-NR_CPUS-to-8192.patch new file mode 100644 index 0000000000000000000000000000000000000000..f90cc109855a5888f075017ef352cd976793b847 --- /dev/null +++ b/0001-ppc64-update-the-NR_CPUS-to-8192.patch @@ -0,0 +1,30 @@ +From ae52398a13fa9a238279114ed671c7c514c154ee Mon Sep 17 00:00:00 2001 +From: Sourabh Jain +Date: Mon, 9 May 2022 12:49:56 +0530 +Subject: [PATCH] ppc64: update the NR_CPUS to 8192 + +Since the kernel commit 2d8ae638bb86 ("powerpc: Make the NR_CPUS max 8192") +the NR_CPUS on Linux kernel ranges from 1-8192. So let's match NR_CPUS with +the max NR_CPUS count on the Linux kernel. + +Signed-off-by: Sourabh Jain +--- + defs.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/defs.h b/defs.h +index 1e8360d65a3b..a6735d07b32f 100644 +--- a/defs.h ++++ b/defs.h +@@ -136,7 +136,7 @@ + #define NR_CPUS (4096) + #endif + #ifdef PPC64 +-#define NR_CPUS (2048) ++#define NR_CPUS (8192) + #endif + #ifdef S390 + #define NR_CPUS (512) +-- +2.30.2 + diff --git a/0001-sbitmapq-remove-struct-and-member-validation-in-sbit.patch b/0001-sbitmapq-remove-struct-and-member-validation-in-sbit.patch new file mode 100644 index 0000000000000000000000000000000000000000..ffca5453f8ee0a12b42bab8e6dcddcd4785a6cda --- /dev/null +++ b/0001-sbitmapq-remove-struct-and-member-validation-in-sbit.patch @@ -0,0 +1,62 @@ +From 364b2e413c69daf189d2bc0238e3ba9b0dcbd937 Mon Sep 17 00:00:00 2001 +From: Lianbo Jiang +Date: Mon, 23 May 2022 18:04:13 +0800 +Subject: [PATCH 01/15] sbitmapq: remove struct and member validation in + sbitmapq_init() + +Let's remove the struct and member validation from sbitmapq_init(), which +will help the crash to display the actual error when the sbitmapq fails. + +Without the patch: + crash> sbitmapq ffff8e99d0dc8010 + sbitmapq: command not supported or applicable on this architecture or kernel + +With the patch: + crash> sbitmapq ffff8e99d0dc8010 + + sbitmapq: invalid structure member offset: sbitmap_queue_alloc_hint + FILE: sbitmap.c LINE: 365 FUNCTION: sbitmap_queue_context_load() + +Signed-off-by: Lianbo Jiang +--- + sbitmap.c | 24 ------------------------ + 1 file changed, 24 deletions(-) + +diff --git a/sbitmap.c b/sbitmap.c +index 96a61e6c2c71..7693eef6cebd 100644 +--- a/sbitmap.c ++++ b/sbitmap.c +@@ -525,30 +525,6 @@ void sbitmapq_init(void) + MEMBER_OFFSET_INIT(sbq_wait_state_wait_cnt, "sbq_wait_state", "wait_cnt"); + MEMBER_OFFSET_INIT(sbq_wait_state_wait, "sbq_wait_state", "wait"); + +- if (!VALID_SIZE(sbitmap_word) || +- !VALID_SIZE(sbitmap) || +- !VALID_SIZE(sbitmap_queue) || +- !VALID_SIZE(sbq_wait_state) || +- INVALID_MEMBER(sbitmap_word_depth) || +- INVALID_MEMBER(sbitmap_word_word) || +- INVALID_MEMBER(sbitmap_word_cleared) || +- INVALID_MEMBER(sbitmap_depth) || +- INVALID_MEMBER(sbitmap_shift) || +- INVALID_MEMBER(sbitmap_map_nr) || +- INVALID_MEMBER(sbitmap_map) || +- INVALID_MEMBER(sbitmap_queue_sb) || +- INVALID_MEMBER(sbitmap_queue_alloc_hint) || +- INVALID_MEMBER(sbitmap_queue_wake_batch) || +- INVALID_MEMBER(sbitmap_queue_wake_index) || +- INVALID_MEMBER(sbitmap_queue_ws) || +- INVALID_MEMBER(sbitmap_queue_ws_active) || +- INVALID_MEMBER(sbitmap_queue_round_robin) || +- INVALID_MEMBER(sbitmap_queue_min_shallow_depth) || +- INVALID_MEMBER(sbq_wait_state_wait_cnt) || +- INVALID_MEMBER(sbq_wait_state_wait)) { +- command_not_supported(); +- } +- + sb_flags |= SB_FLAG_INIT; + } + +-- +2.30.2 + diff --git a/0002-Handle-blk_mq_ctx-member-changes-for-kernels-5.16-rc.patch b/0002-Handle-blk_mq_ctx-member-changes-for-kernels-5.16-rc.patch deleted file mode 100644 index b9091cc5530225f193d78c2f705599b0039adb0d..0000000000000000000000000000000000000000 --- a/0002-Handle-blk_mq_ctx-member-changes-for-kernels-5.16-rc.patch +++ /dev/null @@ -1,101 +0,0 @@ -From 78255e3b33f8d51eb893e662dd1b05a008246b9d Mon Sep 17 00:00:00 2001 -From: Lianbo Jiang -Date: Fri, 24 Dec 2021 18:56:35 +0800 -Subject: [PATCH 02/11] Handle blk_mq_ctx member changes for kernels 5.16-rc1 - and later - -Kernel commit 9a14d6ce4135 ("block: remove debugfs blk_mq_ctx -dispatched/merged/completed attributes") removed the member -rq_dispatched and rq_completed from struct blk_mq_ctx. Without -the patch, "dev -d|-D" options will fail with the following error: - -crash> dev -d -MAJOR GENDISK NAME REQUEST_QUEUE TOTAL ASYNC SYNC - -dev: invalid structure member offset: blk_mq_ctx_rq_dispatched - FILE: dev.c LINE: 4229 FUNCTION: get_one_mctx_diskio() - -Signed-off-by: Lianbo Jiang -Signed-off-by: Kazuhito Hagio ---- - dev.c | 57 +++++++++++++++++++++++++++++++++++++++------------------ - 1 file changed, 39 insertions(+), 18 deletions(-) - -diff --git a/dev.c b/dev.c -index effe789f38d8..a493e51ac95c 100644 ---- a/dev.c -+++ b/dev.c -@@ -4246,6 +4246,10 @@ get_mq_diskio(unsigned long q, unsigned long *mq_count) - unsigned long mctx_addr; - struct diskio tmp; - -+ if (INVALID_MEMBER(blk_mq_ctx_rq_dispatched) || -+ INVALID_MEMBER(blk_mq_ctx_rq_completed)) -+ return; -+ - memset(&tmp, 0x00, sizeof(struct diskio)); - - readmem(q + OFFSET(request_queue_queue_ctx), KVADDR, &queue_ctx, -@@ -4475,24 +4479,41 @@ display_one_diskio(struct iter *i, unsigned long gendisk, ulong flags) - && (io.read + io.write == 0)) - return; - -- fprintf(fp, "%s%s%s %s%s%s%s %s%5d%s%s%s%s%s", -- mkstring(buf0, 5, RJUST|INT_DEC, (char *)(unsigned long)major), -- space(MINSPACE), -- mkstring(buf1, VADDR_PRLEN, LJUST|LONG_HEX, (char *)gendisk), -- space(MINSPACE), -- mkstring(buf2, 10, LJUST, disk_name), -- space(MINSPACE), -- mkstring(buf3, VADDR_PRLEN <= 11 ? 11 : VADDR_PRLEN, -- LJUST|LONG_HEX, (char *)queue_addr), -- space(MINSPACE), -- io.read + io.write, -- space(MINSPACE), -- mkstring(buf4, 5, RJUST|INT_DEC, -- (char *)(unsigned long)io.read), -- space(MINSPACE), -- mkstring(buf5, 5, RJUST|INT_DEC, -- (char *)(unsigned long)io.write), -- space(MINSPACE)); -+ if (use_mq_interface(queue_addr) && -+ (INVALID_MEMBER(blk_mq_ctx_rq_dispatched) || -+ INVALID_MEMBER(blk_mq_ctx_rq_completed))) -+ fprintf(fp, "%s%s%s %s%s%s%s %s%s%s", -+ mkstring(buf0, 5, RJUST|INT_DEC, (char *)(unsigned long)major), -+ space(MINSPACE), -+ mkstring(buf1, VADDR_PRLEN, LJUST|LONG_HEX, (char *)gendisk), -+ space(MINSPACE), -+ mkstring(buf2, 10, LJUST, disk_name), -+ space(MINSPACE), -+ mkstring(buf3, VADDR_PRLEN <= 11 ? 11 : VADDR_PRLEN, -+ LJUST|LONG_HEX, (char *)queue_addr), -+ space(MINSPACE), -+ mkstring(buf4, 17, RJUST, "(not supported)"), -+ space(MINSPACE)); -+ -+ else -+ fprintf(fp, "%s%s%s %s%s%s%s %s%5d%s%s%s%s%s", -+ mkstring(buf0, 5, RJUST|INT_DEC, (char *)(unsigned long)major), -+ space(MINSPACE), -+ mkstring(buf1, VADDR_PRLEN, LJUST|LONG_HEX, (char *)gendisk), -+ space(MINSPACE), -+ mkstring(buf2, 10, LJUST, disk_name), -+ space(MINSPACE), -+ mkstring(buf3, VADDR_PRLEN <= 11 ? 11 : VADDR_PRLEN, -+ LJUST|LONG_HEX, (char *)queue_addr), -+ space(MINSPACE), -+ io.read + io.write, -+ space(MINSPACE), -+ mkstring(buf4, 5, RJUST|INT_DEC, -+ (char *)(unsigned long)io.read), -+ space(MINSPACE), -+ mkstring(buf5, 5, RJUST|INT_DEC, -+ (char *)(unsigned long)io.write), -+ space(MINSPACE)); - - if (VALID_MEMBER(request_queue_in_flight)) { - if (!use_mq_interface(queue_addr)) { --- -2.20.1 - diff --git a/0002-defs.h-fix-breakage-of-compatibility-of-struct-symbo.patch b/0002-defs.h-fix-breakage-of-compatibility-of-struct-symbo.patch deleted file mode 100644 index 1415a8c4f45fdf23ebb8485fcfb64519ad240734..0000000000000000000000000000000000000000 --- a/0002-defs.h-fix-breakage-of-compatibility-of-struct-symbo.patch +++ /dev/null @@ -1,41 +0,0 @@ -From a0eec39c14ee1db95a6c1a649a8f69b97e260dc6 Mon Sep 17 00:00:00 2001 -From: HATAYAMA Daisuke -Date: Wed, 8 Dec 2021 12:07:34 +0000 -Subject: [PATCH 2/2] defs.h: fix breakage of compatibility of struct - symbol_table_data for extension modules - -Commit <3ab39203ddd9> ("symbols: Implement install and remove operations -for mod_symname_hash") added new member variable mod_symname_hash in the -middle of struct symbol_table_date, which breaks compatibility of struct -symbol_table_data for extension modules. As the result, crash trace command -results in segmentation fault. - -Fixes: 3ab39203ddd9 ("symbols: Implement install and remove operations for mod_symname_hash") -Signed-off-by: HATAYAMA Daisuke ---- - defs.h | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/defs.h b/defs.h -index caaa11e50c87..41b6cbc6cc85 100644 ---- a/defs.h -+++ b/defs.h -@@ -2753,7 +2753,6 @@ struct symbol_table_data { - double val_hash_searches; - double val_hash_iterations; - struct syment *symname_hash[SYMNAME_HASH]; -- struct syment *mod_symname_hash[SYMNAME_HASH]; - struct symbol_namespace kernel_namespace; - struct syment *ext_module_symtable; - struct syment *ext_module_symend; -@@ -2780,6 +2779,7 @@ struct symbol_table_data { - ulong kaiser_init_vmlinux; - int kernel_symbol_type; - ulong linux_banner_vmlinux; -+ struct syment *mod_symname_hash[SYMNAME_HASH]; - }; - - /* flags for st */ --- -2.30.2 - diff --git a/0002-sbitmapq-fix-invalid-offset-for-sbitmap_queue_alloc_.patch b/0002-sbitmapq-fix-invalid-offset-for-sbitmap_queue_alloc_.patch new file mode 100644 index 0000000000000000000000000000000000000000..6ee686b95ad74b53c4b1096c89a94a8816e973b4 --- /dev/null +++ b/0002-sbitmapq-fix-invalid-offset-for-sbitmap_queue_alloc_.patch @@ -0,0 +1,118 @@ +From a295cb40cd5d24fb5995cc78d29c5def3843d285 Mon Sep 17 00:00:00 2001 +From: Lianbo Jiang +Date: Mon, 23 May 2022 18:04:14 +0800 +Subject: [PATCH 02/15] sbitmapq: fix invalid offset for + "sbitmap_queue_alloc_hint" on Linux v5.13-rc1 + +Kernel commit c548e62bcf6a ("scsi: sbitmap: Move allocation hint +into sbitmap") moved the alloc_hint member from struct sbitmap_queue +to struct sbitmap. Without the patch, the sbitmapq will fail: + + crash> sbitmapq 0xffff8e99d0dc8010 + + sbitmapq: invalid structure member offset: sbitmap_queue_alloc_hint + FILE: sbitmap.c LINE: 365 FUNCTION: sbitmap_queue_context_load() + +Signed-off-by: Lianbo Jiang +--- + defs.h | 2 ++ + sbitmap.c | 14 ++++++++++++-- + symbols.c | 2 ++ + 3 files changed, 16 insertions(+), 2 deletions(-) + +diff --git a/defs.h b/defs.h +index a6735d07b32f..0aeb98c4f654 100644 +--- a/defs.h ++++ b/defs.h +@@ -2168,6 +2168,7 @@ struct offset_table { /* stash of commonly-used offsets */ + long sbitmap_queue_min_shallow_depth; + long sbq_wait_state_wait_cnt; + long sbq_wait_state_wait; ++ long sbitmap_alloc_hint; + }; + + struct size_table { /* stash of commonly-used sizes */ +@@ -5907,6 +5908,7 @@ struct sbitmap_context { + unsigned shift; + unsigned map_nr; + ulong map_addr; ++ ulong alloc_hint; + }; + + typedef bool (*sbitmap_for_each_fn)(unsigned int idx, void *p); +diff --git a/sbitmap.c b/sbitmap.c +index 7693eef6cebd..2921d5447c65 100644 +--- a/sbitmap.c ++++ b/sbitmap.c +@@ -285,6 +285,7 @@ void sbitmap_for_each_set(const struct sbitmap_context *sc, + static void sbitmap_queue_show(const struct sbitmap_queue_context *sqc, + const struct sbitmap_context *sc) + { ++ ulong alloc_hint_addr = 0; + int cpus = get_cpus_possible(); + int sbq_wait_state_size, wait_cnt_off, wait_off, list_head_off; + char *sbq_wait_state_buf; +@@ -297,6 +298,11 @@ static void sbitmap_queue_show(const struct sbitmap_queue_context *sqc, + fprintf(fp, "bits_per_word = %u\n", 1U << sc->shift); + fprintf(fp, "map_nr = %u\n", sc->map_nr); + ++ if (VALID_MEMBER(sbitmap_queue_alloc_hint)) ++ alloc_hint_addr = sqc->alloc_hint; ++ else if (VALID_MEMBER(sbitmap_alloc_hint)) /* 5.13 and later */ ++ alloc_hint_addr = sc->alloc_hint; ++ + fputs("alloc_hint = {", fp); + first = true; + for (i = 0; i < cpus; i++) { +@@ -307,7 +313,7 @@ static void sbitmap_queue_show(const struct sbitmap_queue_context *sqc, + fprintf(fp, ", "); + first = false; + +- ptr = kt->__per_cpu_offset[i] + sqc->alloc_hint; ++ ptr = kt->__per_cpu_offset[i] + alloc_hint_addr; + readmem(ptr, KVADDR, &val, sizeof(val), "alloc_hint", FAULT_ON_ERROR); + + fprintf(fp, "%u", val); +@@ -362,7 +368,8 @@ static void sbitmap_queue_context_load(ulong addr, struct sbitmap_queue_context + error(FATAL, "cannot read sbitmap_queue\n"); + } + +- sqc->alloc_hint = ULONG(sbitmap_queue_buf + OFFSET(sbitmap_queue_alloc_hint)); ++ if (VALID_MEMBER(sbitmap_queue_alloc_hint)) ++ sqc->alloc_hint = ULONG(sbitmap_queue_buf + OFFSET(sbitmap_queue_alloc_hint)); + sqc->wake_batch = UINT(sbitmap_queue_buf + OFFSET(sbitmap_queue_wake_batch)); + sqc->wake_index = INT(sbitmap_queue_buf + OFFSET(sbitmap_queue_wake_index)); + sqc->ws_addr = ULONG(sbitmap_queue_buf + OFFSET(sbitmap_queue_ws)); +@@ -387,6 +394,8 @@ void sbitmap_context_load(ulong addr, struct sbitmap_context *sc) + sc->shift = UINT(sbitmap_buf + OFFSET(sbitmap_shift)); + sc->map_nr = UINT(sbitmap_buf + OFFSET(sbitmap_map_nr)); + sc->map_addr = ULONG(sbitmap_buf + OFFSET(sbitmap_map)); ++ if (VALID_MEMBER(sbitmap_alloc_hint)) ++ sc->alloc_hint = ULONG(sbitmap_buf + OFFSET(sbitmap_alloc_hint)); + + FREEBUF(sbitmap_buf); + } +@@ -512,6 +521,7 @@ void sbitmapq_init(void) + MEMBER_OFFSET_INIT(sbitmap_shift, "sbitmap", "shift"); + MEMBER_OFFSET_INIT(sbitmap_map_nr, "sbitmap", "map_nr"); + MEMBER_OFFSET_INIT(sbitmap_map, "sbitmap", "map"); ++ MEMBER_OFFSET_INIT(sbitmap_alloc_hint, "sbitmap", "alloc_hint"); + + MEMBER_OFFSET_INIT(sbitmap_queue_sb, "sbitmap_queue", "sb"); + MEMBER_OFFSET_INIT(sbitmap_queue_alloc_hint, "sbitmap_queue", "alloc_hint"); +diff --git a/symbols.c b/symbols.c +index ba5e2741347d..fd0eb06899f0 100644 +--- a/symbols.c ++++ b/symbols.c +@@ -10708,6 +10708,8 @@ dump_offset_table(char *spec, ulong makestruct) + OFFSET(sbitmap_map_nr)); + fprintf(fp, " sbitmap_map: %ld\n", + OFFSET(sbitmap_map)); ++ fprintf(fp, " sbitmap_alloc_hint: %ld\n", ++ OFFSET(sbitmap_alloc_hint)); + fprintf(fp, " sbitmap_queue_sb: %ld\n", + OFFSET(sbitmap_queue_sb)); + fprintf(fp, " sbitmap_queue_alloc_hint: %ld\n", +-- +2.30.2 + diff --git a/0003-Fix-for-timer-r-option-to-display-all-the-per-CPU-cl.patch b/0003-Fix-for-timer-r-option-to-display-all-the-per-CPU-cl.patch deleted file mode 100644 index 4a95e79973f4aef9e10656d5bbfd3b84e129a2aa..0000000000000000000000000000000000000000 --- a/0003-Fix-for-timer-r-option-to-display-all-the-per-CPU-cl.patch +++ /dev/null @@ -1,59 +0,0 @@ -From c48177972f351d7853abb2a57709628c75ee38bc Mon Sep 17 00:00:00 2001 -From: Lianbo Jiang -Date: Thu, 6 Jan 2022 22:34:26 +0800 -Subject: [PATCH 03/11] Fix for "timer -r" option to display all the per-CPU - clocks - -Currently, the hrtimer_max_clock_bases is hard-coded to 3, which -makes that crash only prints three clocks, and the rest of clocks -are not displayed. - -Without the patch: -crash> timer -r -C 11 -CPU: 11 HRTIMER_CPU_BASE: ffff9a775f95ee00 - CLOCK: 0 HRTIMER_CLOCK_BASE: ffff9a775f95ee80 [ktime_get] - (empty) - - CLOCK: 1 HRTIMER_CLOCK_BASE: ffff9a775f95ef00 [ktime_get_real] - (empty) - - CLOCK: 2 HRTIMER_CLOCK_BASE: ffff9a775f95ef80 [ktime_get_boottime] - (empty) - -With the patch: -crash> timer -r -C 11 -CPU: 11 HRTIMER_CPU_BASE: ffff9a775f95ee00 - CLOCK: 0 HRTIMER_CLOCK_BASE: ffff9a775f95ee80 [ktime_get] - (empty) - - CLOCK: 1 HRTIMER_CLOCK_BASE: ffff9a775f95ef00 [ktime_get_real] - (empty) - - CLOCK: 2 HRTIMER_CLOCK_BASE: ffff9a775f95ef80 [ktime_get_boottime] - (empty) -... - CLOCK: 7 HRTIMER_CLOCK_BASE: ffff9a775f95f200 [ktime_get_clocktai] - (empty) - -Signed-off-by: Lianbo Jiang ---- - kernel.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/kernel.c b/kernel.c -index a637dd0eb8f8..a44a9c52ace0 100644 ---- a/kernel.c -+++ b/kernel.c -@@ -7672,7 +7672,8 @@ dump_hrtimer_data(const ulong *cpus) - if (VALID_STRUCT(hrtimer_clock_base)) { - hrtimer_max_clock_bases = 2; - if (symbol_exists("ktime_get_boottime")) -- hrtimer_max_clock_bases = 3; -+ hrtimer_max_clock_bases = MEMBER_SIZE("hrtimer_cpu_base", "clock_base") / -+ SIZE(hrtimer_clock_base); - } else if (VALID_STRUCT(hrtimer_base)) { - max_hrtimer_bases = 2; - } else --- -2.20.1 - diff --git a/0003-LoongArch64-Do-not-verify-temporarily-generated-relo.patch b/0003-LoongArch64-Do-not-verify-temporarily-generated-relo.patch new file mode 100644 index 0000000000000000000000000000000000000000..e0d95ea6ad9a3e33eb276215cf801ed41829cf36 --- /dev/null +++ b/0003-LoongArch64-Do-not-verify-temporarily-generated-relo.patch @@ -0,0 +1,34 @@ +From eeeee24a04dc4a5b888091f206efebda628cf47d Mon Sep 17 00:00:00 2001 +From: Youling Tang +Date: Thu, 3 Mar 2022 15:17:51 +0800 +Subject: [PATCH 3/3] LoongArch64: Do not verify temporarily generated + relocation symbols + +In the LoongArch architecture, due to the implementation of relocation, +many temporary symbols will be generated, which makes it impossible to +enter the crash command line for a long time, so do not verify the +temporarily generated relocation symbols. + +Change-Id: I0543c6a40cddc222508f6bd98ce53608b9cc41db +Signed-off-by: Youling Tang +--- + loongarch64.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/loongarch64.c b/loongarch64.c +index 867bd05..09df05a 100644 +--- a/loongarch64.c ++++ b/loongarch64.c +@@ -1028,6 +1028,9 @@ loongarch64_get_elf_notes(void) + static int + loongarch64_verify_symbol(const char *name, ulong value, char type) + { ++ if (!strncmp(name, ".L", 2) || !strncmp(name, "L0", 2)) ++ return FALSE; ++ + if (CRASHDEBUG(8) && name && strlen(name)) + fprintf(fp, "%08lx %s\n", value, name); + +-- +2.20.1 + diff --git a/0003-sbitmapq-fix-invalid-offset-for-sbitmap_queue_round_.patch b/0003-sbitmapq-fix-invalid-offset-for-sbitmap_queue_round_.patch new file mode 100644 index 0000000000000000000000000000000000000000..0079053ab698a7bf379b23349a0c1903838c2bbc --- /dev/null +++ b/0003-sbitmapq-fix-invalid-offset-for-sbitmap_queue_round_.patch @@ -0,0 +1,103 @@ +From 530fe6ad7e4d7ff6254596c1219d25ed929e3867 Mon Sep 17 00:00:00 2001 +From: Lianbo Jiang +Date: Mon, 23 May 2022 18:04:15 +0800 +Subject: [PATCH 03/15] sbitmapq: fix invalid offset for + "sbitmap_queue_round_robin" on Linux v5.13-rc1 + +Kernel commit efe1f3a1d583 ("scsi: sbitmap: Maintain allocation +round_robin in sbitmap") moved the round_robin member from struct +sbitmap_queue to struct sbitmap. Without the patch, the sbitmapq +will fail: + + crash> sbitmapq 0xffff8e99d0dc8010 + + sbitmapq: invalid structure member offset: sbitmap_queue_round_robin + FILE: sbitmap.c LINE: 378 FUNCTION: sbitmap_queue_context_load() + +Signed-off-by: Lianbo Jiang +--- + defs.h | 2 ++ + sbitmap.c | 12 ++++++++++-- + symbols.c | 2 ++ + 3 files changed, 14 insertions(+), 2 deletions(-) + +diff --git a/defs.h b/defs.h +index 0aeb98c4f654..ecbced24d2e3 100644 +--- a/defs.h ++++ b/defs.h +@@ -2169,6 +2169,7 @@ struct offset_table { /* stash of commonly-used offsets */ + long sbq_wait_state_wait_cnt; + long sbq_wait_state_wait; + long sbitmap_alloc_hint; ++ long sbitmap_round_robin; + }; + + struct size_table { /* stash of commonly-used sizes */ +@@ -5909,6 +5910,7 @@ struct sbitmap_context { + unsigned map_nr; + ulong map_addr; + ulong alloc_hint; ++ bool round_robin; + }; + + typedef bool (*sbitmap_for_each_fn)(unsigned int idx, void *p); +diff --git a/sbitmap.c b/sbitmap.c +index 2921d5447c65..7b318b533702 100644 +--- a/sbitmap.c ++++ b/sbitmap.c +@@ -352,7 +352,11 @@ static void sbitmap_queue_show(const struct sbitmap_queue_context *sqc, + + FREEBUF(sbq_wait_state_buf); + +- fprintf(fp, "round_robin = %d\n", sqc->round_robin); ++ if (VALID_MEMBER(sbitmap_queue_round_robin)) ++ fprintf(fp, "round_robin = %d\n", sqc->round_robin); ++ else if (VALID_MEMBER(sbitmap_round_robin)) /* 5.13 and later */ ++ fprintf(fp, "round_robin = %d\n", sc->round_robin); ++ + fprintf(fp, "min_shallow_depth = %u\n", sqc->min_shallow_depth); + } + +@@ -374,7 +378,8 @@ static void sbitmap_queue_context_load(ulong addr, struct sbitmap_queue_context + sqc->wake_index = INT(sbitmap_queue_buf + OFFSET(sbitmap_queue_wake_index)); + sqc->ws_addr = ULONG(sbitmap_queue_buf + OFFSET(sbitmap_queue_ws)); + sqc->ws_active = INT(sbitmap_queue_buf + OFFSET(sbitmap_queue_ws_active)); +- sqc->round_robin = BOOL(sbitmap_queue_buf + OFFSET(sbitmap_queue_round_robin)); ++ if (VALID_MEMBER(sbitmap_queue_round_robin)) ++ sqc->round_robin = BOOL(sbitmap_queue_buf + OFFSET(sbitmap_queue_round_robin)); + sqc->min_shallow_depth = UINT(sbitmap_queue_buf + OFFSET(sbitmap_queue_min_shallow_depth)); + + FREEBUF(sbitmap_queue_buf); +@@ -396,6 +401,8 @@ void sbitmap_context_load(ulong addr, struct sbitmap_context *sc) + sc->map_addr = ULONG(sbitmap_buf + OFFSET(sbitmap_map)); + if (VALID_MEMBER(sbitmap_alloc_hint)) + sc->alloc_hint = ULONG(sbitmap_buf + OFFSET(sbitmap_alloc_hint)); ++ if (VALID_MEMBER(sbitmap_round_robin)) ++ sc->round_robin = BOOL(sbitmap_buf + OFFSET(sbitmap_round_robin)); + + FREEBUF(sbitmap_buf); + } +@@ -522,6 +529,7 @@ void sbitmapq_init(void) + MEMBER_OFFSET_INIT(sbitmap_map_nr, "sbitmap", "map_nr"); + MEMBER_OFFSET_INIT(sbitmap_map, "sbitmap", "map"); + MEMBER_OFFSET_INIT(sbitmap_alloc_hint, "sbitmap", "alloc_hint"); ++ MEMBER_OFFSET_INIT(sbitmap_round_robin, "sbitmap", "round_robin"); + + MEMBER_OFFSET_INIT(sbitmap_queue_sb, "sbitmap_queue", "sb"); + MEMBER_OFFSET_INIT(sbitmap_queue_alloc_hint, "sbitmap_queue", "alloc_hint"); +diff --git a/symbols.c b/symbols.c +index fd0eb06899f0..5d12a021c769 100644 +--- a/symbols.c ++++ b/symbols.c +@@ -10710,6 +10710,8 @@ dump_offset_table(char *spec, ulong makestruct) + OFFSET(sbitmap_map)); + fprintf(fp, " sbitmap_alloc_hint: %ld\n", + OFFSET(sbitmap_alloc_hint)); ++ fprintf(fp, " sbitmap_round_robin: %ld\n", ++ OFFSET(sbitmap_round_robin)); + fprintf(fp, " sbitmap_queue_sb: %ld\n", + OFFSET(sbitmap_queue_sb)); + fprintf(fp, " sbitmap_queue_alloc_hint: %ld\n", +-- +2.30.2 + diff --git a/0004-Fix-for-bt-v-option-to-display-the-stack-end-address.patch b/0004-Fix-for-bt-v-option-to-display-the-stack-end-address.patch deleted file mode 100644 index 0c56e07770456bc2d1dfb3b716ac237c436c69b5..0000000000000000000000000000000000000000 --- a/0004-Fix-for-bt-v-option-to-display-the-stack-end-address.patch +++ /dev/null @@ -1,69 +0,0 @@ -From 1706f8b6ab50cd25e8fdabe8d50a37ce89bd60e0 Mon Sep 17 00:00:00 2001 -From: Lianbo Jiang -Date: Thu, 6 Jan 2022 12:01:17 +0800 -Subject: [PATCH 04/11] Fix for "bt -v" option to display the stack-end address - correctly - -The "bt -v" command prints incorrect stack-end address when the -"CONFIG_THREAD_INFO_IN_TASK=y" is enabled in kernel, the "bt -v" -command output shows that the value stored at 0xffff8dee0312c198 -is 0xffffffffc076400a, however, the value stored actually at -0xffff8dee0312c198 is NULL(0x0000000000000000), the stack-end -address is incorrect. - -Without the patch: -crash> bt -v -PID: 28642 TASK: ffff8dee0312c180 CPU: 0 COMMAND: "insmod" - possible stack overflow: ffff8dee0312c198: ffffffffc076400a != STACK_END_MAGIC - ^^^^^^^^^^^^^^^^ - -crash> rd 0xffff8dee0312c198 -ffff8dee0312c198: 0000000000000000 ........ - ^^^^^^^^^^^^^^^^ - -With the patch: -crash> bt -v -PID: 28642 TASK: ffff8dee0312c180 CPU: 0 COMMAND: "insmod" - possible stack overflow: ffff991340bc0000: ffffffffc076400a != STACK_END_MAGIC - -crash> rd 0xffff991340bc0000 -ffff991340bc0000: ffffffffc076400a .@v..... - -Signed-off-by: Lianbo Jiang ---- - task.c | 10 ++++++++-- - 1 file changed, 8 insertions(+), 2 deletions(-) - -diff --git a/task.c b/task.c -index bb6a5da8ad33..b5ddc88e0acb 100644 ---- a/task.c -+++ b/task.c -@@ -11202,7 +11202,7 @@ check_stack_overflow(void) - { - int i, overflow, cpu_size, cpu, total; - char buf[BUFSIZE]; -- ulong magic, task, stackbase; -+ ulong magic, task, stackbase, location; - struct task_context *tc; - - if (!tt->stack_end_magic && -@@ -11286,9 +11286,15 @@ check_stack_end_magic: - if (magic != STACK_END_MAGIC) { - if (!overflow) - print_task_header(fp, tc, 0); -+ -+ if (tt->flags & THREAD_INFO_IN_TASK) -+ location = task_to_stackbase(tc->task); -+ else -+ location = tc->thread_info + SIZE(thread_info); -+ - fprintf(fp, - " possible stack overflow: %lx: %lx != STACK_END_MAGIC\n", -- tc->thread_info + SIZE(thread_info), magic); -+ location, magic); - overflow++, total++; - } - --- -2.20.1 - diff --git a/0004-sbitmapq-fix-invalid-offset-for-sbitmap_word_depth-o.patch b/0004-sbitmapq-fix-invalid-offset-for-sbitmap_word_depth-o.patch new file mode 100644 index 0000000000000000000000000000000000000000..07edd5bb0c8b5bbb4d9867a70e56c8432e64de54 --- /dev/null +++ b/0004-sbitmapq-fix-invalid-offset-for-sbitmap_word_depth-o.patch @@ -0,0 +1,101 @@ +From 3750803f6ae5f5ad071f86ca916dbbb17b7a83a5 Mon Sep 17 00:00:00 2001 +From: Lianbo Jiang +Date: Mon, 23 May 2022 18:04:16 +0800 +Subject: [PATCH 04/15] sbitmapq: fix invalid offset for "sbitmap_word_depth" + on Linux v5.18-rc1 + +Kernel commit 3301bc53358a ("lib/sbitmap: kill 'depth' from sbitmap_word") +removed the depth member from struct sbitmap_word. Without the patch, the +sbitmapq will fail: + + crash> sbitmapq 0xffff8e99d0dc8010 + + sbitmapq: invalid structure member offset: sbitmap_word_depth + FILE: sbitmap.c LINE: 84 FUNCTION: __sbitmap_weight() + +Signed-off-by: Lianbo Jiang +--- + sbitmap.c | 19 +++++++++++-------- + 1 file changed, 11 insertions(+), 8 deletions(-) + +diff --git a/sbitmap.c b/sbitmap.c +index 7b318b533702..e8ebd62fe01c 100644 +--- a/sbitmap.c ++++ b/sbitmap.c +@@ -78,10 +78,16 @@ static unsigned long bitmap_weight(unsigned long bitmap, unsigned int bits) + return w; + } + ++static inline unsigned int __map_depth(const struct sbitmap_context *sc, int index) ++{ ++ if (index == sc->map_nr - 1) ++ return sc->depth - (index << sc->shift); ++ return 1U << sc->shift; ++} ++ + static unsigned int __sbitmap_weight(const struct sbitmap_context *sc, bool set) + { + const ulong sbitmap_word_size = SIZE(sbitmap_word); +- const ulong w_depth_off = OFFSET(sbitmap_word_depth); + const ulong w_word_off = OFFSET(sbitmap_word_word); + const ulong w_cleared_off = OFFSET(sbitmap_word_cleared); + +@@ -99,7 +105,7 @@ static unsigned int __sbitmap_weight(const struct sbitmap_context *sc, bool set) + error(FATAL, "cannot read sbitmap_word\n"); + } + +- depth = ULONG(sbitmap_word_buf + w_depth_off); ++ depth = __map_depth(sc, i); + + if (set) { + word = ULONG(sbitmap_word_buf + w_word_off); +@@ -142,7 +148,6 @@ static void sbitmap_emit_byte(unsigned int offset, uint8_t byte) + static void sbitmap_bitmap_show(const struct sbitmap_context *sc) + { + const ulong sbitmap_word_size = SIZE(sbitmap_word); +- const ulong w_depth_off = OFFSET(sbitmap_word_depth); + const ulong w_word_off = OFFSET(sbitmap_word_word); + const ulong w_cleared_off = OFFSET(sbitmap_word_cleared); + +@@ -165,7 +170,7 @@ static void sbitmap_bitmap_show(const struct sbitmap_context *sc) + + word = ULONG(sbitmap_word_buf + w_word_off); + cleared = ULONG(sbitmap_word_buf + w_cleared_off); +- word_bits = ULONG(sbitmap_word_buf + w_depth_off); ++ word_bits = __map_depth(sc, i); + + word &= ~cleared; + +@@ -213,7 +218,6 @@ static void __sbitmap_for_each_set(const struct sbitmap_context *sc, + unsigned int start, sbitmap_for_each_fn fn, void *data) + { + const ulong sbitmap_word_size = SIZE(sbitmap_word); +- const ulong w_depth_off = OFFSET(sbitmap_word_depth); + const ulong w_word_off = OFFSET(sbitmap_word_word); + const ulong w_cleared_off = OFFSET(sbitmap_word_cleared); + +@@ -232,7 +236,7 @@ static void __sbitmap_for_each_set(const struct sbitmap_context *sc, + + while (scanned < sc->depth) { + unsigned long w_addr = sc->map_addr + (sbitmap_word_size * index); +- unsigned long w_depth, w_word, w_cleared; ++ unsigned long w_word, w_cleared; + unsigned long word, depth; + + if (!readmem(w_addr, KVADDR, sbitmap_word_buf, sbitmap_word_size, "sbitmap_word", RETURN_ON_ERROR)) { +@@ -240,11 +244,10 @@ static void __sbitmap_for_each_set(const struct sbitmap_context *sc, + error(FATAL, "cannot read sbitmap_word\n"); + } + +- w_depth = ULONG(sbitmap_word_buf + w_depth_off); + w_word = ULONG(sbitmap_word_buf + w_word_off); + w_cleared = ULONG(sbitmap_word_buf + w_cleared_off); + +- depth = min(w_depth - nr, sc->depth - scanned); ++ depth = min(__map_depth(sc, index) - nr, sc->depth - scanned); + + scanned += depth; + word = w_word & ~w_cleared; +-- +2.30.2 + diff --git a/0005-Fix-for-HZ-calculation-on-Linux-5.14-and-later.patch b/0005-Fix-for-HZ-calculation-on-Linux-5.14-and-later.patch deleted file mode 100644 index f249f7222703cb197bd3f47916379829a78512ec..0000000000000000000000000000000000000000 --- a/0005-Fix-for-HZ-calculation-on-Linux-5.14-and-later.patch +++ /dev/null @@ -1,35 +0,0 @@ -From f5637f341533ef2b28e2d6a6b12fcfb00d0fff2d Mon Sep 17 00:00:00 2001 -From: Lianbo Jiang -Date: Mon, 10 Jan 2022 17:25:06 +0800 -Subject: [PATCH 05/11] Fix for HZ calculation on Linux 5.14 and later - -Kernel commit 3e9a99eba058 ("block/mq-deadline: Rename dd_init_queue() -and dd_exit_queue()") renamed dd_init_queue to dd_init_sched. Without -the patch, the 'help -m' may print incorrect hz value as follows: - -crash> help -m | grep hz - hz: 1000 <---The correct hz value on ppc64le machine is 100. - ^^^^ - -Fixes: b93027ce5c75 ("Add alternate HZ calculation using write_expire") -Signed-off-by: Lianbo Jiang ---- - task.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/task.c b/task.c -index b5ddc88e0acb..76e184ae70b1 100644 ---- a/task.c -+++ b/task.c -@@ -440,6 +440,8 @@ task_init(void) - } - } else if ((symbol_exists("dd_init_queue") && - gdb_set_crash_scope(symbol_value("dd_init_queue"), "dd_init_queue")) || -+ (symbol_exists("dd_init_sched") && -+ gdb_set_crash_scope(symbol_value("dd_init_sched"), "dd_init_sched")) || - (symbol_exists("deadline_init_queue") && - gdb_set_crash_scope(symbol_value("deadline_init_queue"), "deadline_init_queue"))) { - char buf[BUFSIZE]; --- -2.20.1 - diff --git a/0005-Makefile-add-missing-crash_target.o-to-be-cleaned.patch b/0005-Makefile-add-missing-crash_target.o-to-be-cleaned.patch new file mode 100644 index 0000000000000000000000000000000000000000..5fd1f7bcecadeebe69a5ed34857d2721085f834e --- /dev/null +++ b/0005-Makefile-add-missing-crash_target.o-to-be-cleaned.patch @@ -0,0 +1,26 @@ +From 9705669a49c341402efd8528e8fe809379dd798d Mon Sep 17 00:00:00 2001 +From: Kazuhito Hagio +Date: Mon, 23 May 2022 14:48:50 +0900 +Subject: [PATCH 05/15] Makefile: add missing crash_target.o to be cleaned + +Signed-off-by: Kazuhito Hagio +--- + Makefile | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/Makefile b/Makefile +index e520b1217a9d..162c2baa5164 100644 +--- a/Makefile ++++ b/Makefile +@@ -184,7 +184,7 @@ GDB_7.6_FILES= + GDB_7.6_OFILES=${GDB}/gdb/symtab.o + + GDB_10.2_FILES= +-GDB_10.2_OFILES=${GDB}/gdb/symtab.o ++GDB_10.2_OFILES=${GDB}/gdb/symtab.o crash_target.o + + # + # GDB_FLAGS is passed up from the gdb Makefile. +-- +2.30.2 + diff --git a/0006-bt-x86_64-filter-out-idle-task-stack.patch b/0006-bt-x86_64-filter-out-idle-task-stack.patch new file mode 100644 index 0000000000000000000000000000000000000000..885f71f96b33228038af0b1a7a20d7691ad8d05a --- /dev/null +++ b/0006-bt-x86_64-filter-out-idle-task-stack.patch @@ -0,0 +1,204 @@ +From 6833262bf87177d8affe4f91b2e7d2c76ecdf636 Mon Sep 17 00:00:00 2001 +From: Qi Zheng +Date: Tue, 24 May 2022 20:25:53 +0800 +Subject: [PATCH 06/15] bt: x86_64: filter out idle task stack + +When we use crash to troubleshoot softlockup and other problems, +we often use the 'bt -a' command to print the stacks of running +processes on all CPUs. But now some servers have hundreds of CPUs +(such as AMD machines), which causes the 'bt -a' command to output +a lot of process stacks. And many of these stacks are the stacks +of the idle process, which are not needed by us. + +Therefore, in order to reduce this part of the interference information, +this patch adds the -n option to the bt command. When we specify +'-n idle' (meaning no idle), the stack of the idle process will be +filtered out, thus speeding up our troubleshooting. + +And the option works only for crash dumps captured by kdump. + +The command output is as follows: +crash> bt -a -n idle +[...] +PID: 0 TASK: ffff889ff8c34380 CPU: 8 COMMAND: "swapper/8" + +PID: 0 TASK: ffff889ff8c32d00 CPU: 9 COMMAND: "swapper/9" + +PID: 0 TASK: ffff889ff8c31680 CPU: 10 COMMAND: "swapper/10" + +PID: 0 TASK: ffff889ff8c35a00 CPU: 11 COMMAND: "swapper/11" + +PID: 0 TASK: ffff889ff8c3c380 CPU: 12 COMMAND: "swapper/12" + +PID: 150773 TASK: ffff889fe85a1680 CPU: 13 COMMAND: "bash" + #0 [ffffc9000d35bcd0] machine_kexec at ffffffff8105a407 + #1 [ffffc9000d35bd28] __crash_kexec at ffffffff8113033d + #2 [ffffc9000d35bdf0] panic at ffffffff81081930 + #3 [ffffc9000d35be70] sysrq_handle_crash at ffffffff814e38d1 + #4 [ffffc9000d35be78] __handle_sysrq.cold.12 at ffffffff814e4175 + #5 [ffffc9000d35bea8] write_sysrq_trigger at ffffffff814e404b + #6 [ffffc9000d35beb8] proc_reg_write at ffffffff81330d86 + #7 [ffffc9000d35bed0] vfs_write at ffffffff812a72d5 + #8 [ffffc9000d35bf00] ksys_write at ffffffff812a7579 + #9 [ffffc9000d35bf38] do_syscall_64 at ffffffff81004259 + RIP: 00007fa7abcdc274 RSP: 00007fffa731f678 RFLAGS: 00000246 + RAX: ffffffffffffffda RBX: 0000000000000002 RCX: 00007fa7abcdc274 + RDX: 0000000000000002 RSI: 0000563ca51ee6d0 RDI: 0000000000000001 + RBP: 0000563ca51ee6d0 R8: 000000000000000a R9: 00007fa7abd6be80 + R10: 000000000000000a R11: 0000000000000246 R12: 00007fa7abdad760 + R13: 0000000000000002 R14: 00007fa7abda8760 R15: 0000000000000002 + ORIG_RAX: 0000000000000001 CS: 0033 SS: 002b +[...] + +Signed-off-by: Qi Zheng +Acked-by: Kazuhito Hagio +Acked-by: Lianbo Jiang +--- + defs.h | 1 + + help.c | 33 ++++++++++++++++++++++++++++++++- + kernel.c | 13 ++++++++++++- + x86_64.c | 8 ++++++++ + 4 files changed, 53 insertions(+), 2 deletions(-) + +diff --git a/defs.h b/defs.h +index ecbced24d2e3..c8444b4e54eb 100644 +--- a/defs.h ++++ b/defs.h +@@ -5832,6 +5832,7 @@ ulong cpu_map_addr(const char *type); + #define BT_SHOW_ALL_REGS (0x2000000000000ULL) + #define BT_REGS_NOT_FOUND (0x4000000000000ULL) + #define BT_OVERFLOW_STACK (0x8000000000000ULL) ++#define BT_SKIP_IDLE (0x10000000000000ULL) + #define BT_SYMBOL_OFFSET (BT_SYMBOLIC_ARGS) + + #define BT_REF_HEXVAL (0x1) +diff --git a/help.c b/help.c +index 51a0fe3d687c..e1bbc5abe029 100644 +--- a/help.c ++++ b/help.c +@@ -1909,12 +1909,14 @@ char *help_bt[] = { + "bt", + "backtrace", + "[-a|-c cpu(s)|-g|-r|-t|-T|-l|-e|-E|-f|-F|-o|-O|-v|-p] [-R ref] [-s [-x|d]]" +-"\n [-I ip] [-S sp] [pid | task]", ++"\n [-I ip] [-S sp] [-n idle] [pid | task]", + " Display a kernel stack backtrace. If no arguments are given, the stack", + " trace of the current context will be displayed.\n", + " -a displays the stack traces of the active task on each CPU.", + " (only applicable to crash dumps)", + " -A same as -a, but also displays vector registers (S390X only).", ++" -n idle filter the stack of idle tasks (x86_64).", ++" (only applicable to crash dumps)", + " -p display the stack trace of the panic task only.", + " (only applicable to crash dumps)", + " -c cpu display the stack trace of the active task on one or more CPUs,", +@@ -2004,6 +2006,35 @@ char *help_bt[] = { + " DS: 002b ESI: bfffc8a0 ES: 002b EDI: 00000000 ", + " SS: 002b ESP: bfffc82c EBP: bfffd224 ", + " CS: 0023 EIP: 400d032e ERR: 0000008e EFLAGS: 00000246 ", ++" ", ++" Display the stack trace of the active task(s) when the kernel panicked,", ++" and filter out the stack of the idle tasks:", ++" ", ++" %s> bt -a -n idle", ++" ...", ++" PID: 0 TASK: ffff889ff8c35a00 CPU: 11 COMMAND: \"swapper/11\"", ++" ", ++" PID: 0 TASK: ffff889ff8c3c380 CPU: 12 COMMAND: \"swapper/12\"", ++" ", ++" PID: 150773 TASK: ffff889fe85a1680 CPU: 13 COMMAND: \"bash\"", ++" #0 [ffffc9000d35bcd0] machine_kexec at ffffffff8105a407", ++" #1 [ffffc9000d35bd28] __crash_kexec at ffffffff8113033d", ++" #2 [ffffc9000d35bdf0] panic at ffffffff81081930", ++" #3 [ffffc9000d35be70] sysrq_handle_crash at ffffffff814e38d1", ++" #4 [ffffc9000d35be78] __handle_sysrq.cold.12 at ffffffff814e4175", ++" #5 [ffffc9000d35bea8] write_sysrq_trigger at ffffffff814e404b", ++" #6 [ffffc9000d35beb8] proc_reg_write at ffffffff81330d86", ++" #7 [ffffc9000d35bed0] vfs_write at ffffffff812a72d5", ++" #8 [ffffc9000d35bf00] ksys_write at ffffffff812a7579", ++" #9 [ffffc9000d35bf38] do_syscall_64 at ffffffff81004259", ++" RIP: 00007fa7abcdc274 RSP: 00007fffa731f678 RFLAGS: 00000246", ++" RAX: ffffffffffffffda RBX: 0000000000000002 RCX: 00007fa7abcdc274", ++" RDX: 0000000000000002 RSI: 0000563ca51ee6d0 RDI: 0000000000000001", ++" RBP: 0000563ca51ee6d0 R8: 000000000000000a R9: 00007fa7abd6be80", ++" R10: 000000000000000a R11: 0000000000000246 R12: 00007fa7abdad760", ++" R13: 0000000000000002 R14: 00007fa7abda8760 R15: 0000000000000002", ++" ORIG_RAX: 0000000000000001 CS: 0033 SS: 002b", ++" ...", + "\n Display the stack trace of the active task on CPU 0 and 1:\n", + " %s> bt -c 0,1", + " PID: 0 TASK: ffffffff81a8d020 CPU: 0 COMMAND: \"swapper\"", +diff --git a/kernel.c b/kernel.c +index d0921cf567d9..411e9da1e54f 100644 +--- a/kernel.c ++++ b/kernel.c +@@ -2503,7 +2503,7 @@ cmd_bt(void) + if (kt->flags & USE_OPT_BT) + bt->flags |= BT_OPT_BACK_TRACE; + +- while ((c = getopt(argcnt, args, "D:fFI:S:c:aAloreEgstTdxR:Ovp")) != EOF) { ++ while ((c = getopt(argcnt, args, "D:fFI:S:c:n:aAloreEgstTdxR:Ovp")) != EOF) { + switch (c) + { + case 'f': +@@ -2672,6 +2672,13 @@ cmd_bt(void) + active++; + break; + ++ case 'n': ++ if (machine_type("X86_64") && STREQ(optarg, "idle")) ++ bt->flags |= BT_SKIP_IDLE; ++ else ++ option_not_supported(c); ++ break; ++ + case 'r': + bt->flags |= BT_RAW; + break; +@@ -3092,6 +3099,10 @@ back_trace(struct bt_info *bt) + } else + machdep->get_stack_frame(bt, &eip, &esp); + ++ /* skip idle task stack */ ++ if (bt->flags & BT_SKIP_IDLE) ++ return; ++ + if (bt->flags & BT_KSTACKP) { + bt->stkptr = esp; + return; +diff --git a/x86_64.c b/x86_64.c +index ecaefd2f46a8..cfafbcc4dabe 100644 +--- a/x86_64.c ++++ b/x86_64.c +@@ -4918,6 +4918,9 @@ x86_64_get_stack_frame(struct bt_info *bt, ulong *pcp, ulong *spp) + if (bt->flags & BT_DUMPFILE_SEARCH) + return x86_64_get_dumpfile_stack_frame(bt, pcp, spp); + ++ if (bt->flags & BT_SKIP_IDLE) ++ bt->flags &= ~BT_SKIP_IDLE; ++ + if (pcp) + *pcp = x86_64_get_pc(bt); + if (spp) +@@ -4960,6 +4963,9 @@ x86_64_get_dumpfile_stack_frame(struct bt_info *bt_in, ulong *rip, ulong *rsp) + estack = -1; + panic = FALSE; + ++ if (bt_in->flags & BT_SKIP_IDLE) ++ bt_in->flags &= ~BT_SKIP_IDLE; ++ + panic_task = tt->panic_task == bt->task ? TRUE : FALSE; + + if (panic_task && bt->machdep) { +@@ -5098,6 +5104,8 @@ next_sysrq: + if (!panic_task && STREQ(sym, "crash_nmi_callback")) { + *rip = *up; + *rsp = bt->stackbase + ((char *)(up) - bt->stackbuf); ++ if ((bt->flags & BT_SKIP_IDLE) && is_idle_thread(bt->task)) ++ bt_in->flags |= BT_SKIP_IDLE; + return; + } + +-- +2.30.2 + diff --git a/0006-memory-Handle-struct-slab-changes-on-Linux-5.17-rc1-.patch b/0006-memory-Handle-struct-slab-changes-on-Linux-5.17-rc1-.patch deleted file mode 100644 index 740730649ab5d338f651e03a5368ff96311eb36e..0000000000000000000000000000000000000000 --- a/0006-memory-Handle-struct-slab-changes-on-Linux-5.17-rc1-.patch +++ /dev/null @@ -1,40 +0,0 @@ -From a392b27653e4e75460753522af0f006006b4dc4e Mon Sep 17 00:00:00 2001 -From: Alexander Egorenkov -Date: Mon, 6 Dec 2021 16:04:19 +0100 -Subject: [PATCH 06/11] memory: Handle struct slab changes on Linux 5.17-rc1 - and later - -Since kernel commit d122019bf061 ("mm: Split slab into its own type"), -the struct slab is used for both SLAB and SLUB. Therefore, don't depend -on the non-presence of the struct slab to decide whether SLAB implementation -should be chosen and use the member variable "cpu_slab" of the struct -kmem_cache instead, it should be present only in SLUB. - -Without the patch, crash fails to start with the error message: - - crash: invalid structure member offset: kmem_cache_s_num - FILE: memory.c LINE: 9619 FUNCTION: kmem_cache_init() - -Signed-off-by: Alexander Egorenkov -Signed-off-by: Lianbo Jiang ---- - memory.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/memory.c b/memory.c -index 86c02c132890..5af45fd7d834 100644 ---- a/memory.c -+++ b/memory.c -@@ -576,7 +576,8 @@ vm_init(void) - STRUCT_SIZE_INIT(cpucache_s, "cpucache_s"); - - } else if (!VALID_STRUCT(kmem_slab_s) && -- !VALID_STRUCT(slab_s) && -+ !VALID_STRUCT(slab_s) && -+ !MEMBER_EXISTS("kmem_cache", "cpu_slab") && - (VALID_STRUCT(slab) || (vt->flags & SLAB_OVERLOAD_PAGE))) { - vt->flags |= PERCPU_KMALLOC_V2; - --- -2.20.1 - diff --git a/0007-Move-the-initialization-of-boot_date-to-task_init.patch b/0007-Move-the-initialization-of-boot_date-to-task_init.patch deleted file mode 100644 index c8d82275a09fc7ea009a9b536ac0a193fb89e67b..0000000000000000000000000000000000000000 --- a/0007-Move-the-initialization-of-boot_date-to-task_init.patch +++ /dev/null @@ -1,75 +0,0 @@ -From fa0b6453a05c5600849e4e531c94594ed9c90270 Mon Sep 17 00:00:00 2001 -From: Lianbo Jiang -Date: Mon, 17 Jan 2022 15:14:00 +0800 -Subject: [PATCH 07/11] Move the initialization of "boot_date" to task_init() - -The "boot_date" is initialized conditionally in the cmd_log(), which may -display incorrect "boot_date" value with the following command before -running the "log -T" command: - -crash> help -k | grep date - date: Wed Dec 22 13:39:29 IST 2021 - boot_date: Thu Jan 1 05:30:00 IST 1970 - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -The calculation of "boot_date" depends on the HZ value, and the HZ will -be calculated in task_init() at the latest, so let's move it here. - -Signed-off-by: Lianbo Jiang ---- - kernel.c | 18 +++--------------- - task.c | 10 ++++++++++ - 2 files changed, 13 insertions(+), 15 deletions(-) - -diff --git a/kernel.c b/kernel.c -index a44a9c52ace0..9afddc0c918c 100644 ---- a/kernel.c -+++ b/kernel.c -@@ -5026,21 +5026,9 @@ cmd_log(void) - if (argerrs) - cmd_usage(pc->curcmd, SYNOPSIS); - -- if (msg_flags & SHOW_LOG_CTIME) { -- if (pc->flags & MINIMAL_MODE) { -- error(WARNING, "the option '-T' is not available in minimal mode\n"); -- return; -- } -- -- if (kt->boot_date.tv_sec == 0) { -- ulonglong uptime_jiffies; -- ulong uptime_sec; -- -- get_uptime(NULL, &uptime_jiffies); -- uptime_sec = (uptime_jiffies)/(ulonglong)machdep->hz; -- kt->boot_date.tv_sec = kt->date.tv_sec - uptime_sec; -- kt->boot_date.tv_nsec = 0; -- } -+ if (msg_flags & SHOW_LOG_CTIME && pc->flags & MINIMAL_MODE) { -+ error(WARNING, "the option '-T' is not available in minimal mode\n"); -+ return; - } - - if (msg_flags & SHOW_LOG_AUDIT) { -diff --git a/task.c b/task.c -index 76e184ae70b1..263a8344dd94 100644 ---- a/task.c -+++ b/task.c -@@ -692,6 +692,16 @@ task_init(void) - - stack_overflow_check_init(); - -+ if (machdep->hz) { -+ ulonglong uptime_jiffies; -+ ulong uptime_sec; -+ -+ get_uptime(NULL, &uptime_jiffies); -+ uptime_sec = (uptime_jiffies)/(ulonglong)machdep->hz; -+ kt->boot_date.tv_sec = kt->date.tv_sec - uptime_sec; -+ kt->boot_date.tv_nsec = 0; -+ } -+ - tt->flags |= TASK_INIT_DONE; - } - --- -2.20.1 - diff --git a/0007-bt-arm64-add-support-for-bt-n-idle.patch b/0007-bt-arm64-add-support-for-bt-n-idle.patch new file mode 100644 index 0000000000000000000000000000000000000000..b5c6b7616da6729052119e79c899c7ba5a8cf82c --- /dev/null +++ b/0007-bt-arm64-add-support-for-bt-n-idle.patch @@ -0,0 +1,95 @@ +From 0f162febebc4d11a165dd40cee00f3b0ba691a52 Mon Sep 17 00:00:00 2001 +From: Qi Zheng +Date: Tue, 24 May 2022 20:25:54 +0800 +Subject: [PATCH 07/15] bt: arm64: add support for 'bt -n idle' + +The '-n idle' option of bt command can help us filter the +stack of the idle process when debugging the dumpfiles +captured by kdump. + +This patch supports this feature on ARM64. + +Signed-off-by: Qi Zheng +--- + arm64.c | 19 ++++++++++++++++--- + help.c | 2 +- + kernel.c | 3 ++- + 3 files changed, 19 insertions(+), 5 deletions(-) + +diff --git a/arm64.c b/arm64.c +index 65f6cdf69fa6..0f615cf52bef 100644 +--- a/arm64.c ++++ b/arm64.c +@@ -3681,6 +3681,12 @@ arm64_get_dumpfile_stackframe(struct bt_info *bt, struct arm64_stackframe *frame + { + struct machine_specific *ms = machdep->machspec; + struct arm64_pt_regs *ptregs; ++ bool skip = false; ++ ++ if (bt->flags & BT_SKIP_IDLE) { ++ skip = true; ++ bt->flags &= ~BT_SKIP_IDLE; ++ } + + if (!ms->panic_task_regs || + (!ms->panic_task_regs[bt->tc->processor].sp && +@@ -3713,8 +3719,11 @@ try_kernel: + } + + if (arm64_in_kdump_text(bt, frame) || +- arm64_in_kdump_text_on_irq_stack(bt)) ++ arm64_in_kdump_text_on_irq_stack(bt)) { + bt->flags |= BT_KDUMP_ADJUST; ++ if (skip && is_idle_thread(bt->task)) ++ bt->flags |= BT_SKIP_IDLE; ++ } + + return TRUE; + } +@@ -3738,10 +3747,14 @@ arm64_get_stack_frame(struct bt_info *bt, ulong *pcp, ulong *spp) + int ret; + struct arm64_stackframe stackframe = { 0 }; + +- if (DUMPFILE() && is_task_active(bt->task)) ++ if (DUMPFILE() && is_task_active(bt->task)) { + ret = arm64_get_dumpfile_stackframe(bt, &stackframe); +- else ++ } else { ++ if (bt->flags & BT_SKIP_IDLE) ++ bt->flags &= ~BT_SKIP_IDLE; ++ + ret = arm64_get_stackframe(bt, &stackframe); ++ } + + if (!ret) + error(WARNING, +diff --git a/help.c b/help.c +index e1bbc5abe029..99214c1590fa 100644 +--- a/help.c ++++ b/help.c +@@ -1915,7 +1915,7 @@ char *help_bt[] = { + " -a displays the stack traces of the active task on each CPU.", + " (only applicable to crash dumps)", + " -A same as -a, but also displays vector registers (S390X only).", +-" -n idle filter the stack of idle tasks (x86_64).", ++" -n idle filter the stack of idle tasks (x86_64, arm64).", + " (only applicable to crash dumps)", + " -p display the stack trace of the panic task only.", + " (only applicable to crash dumps)", +diff --git a/kernel.c b/kernel.c +index 411e9da1e54f..a521ef30cdb0 100644 +--- a/kernel.c ++++ b/kernel.c +@@ -2673,7 +2673,8 @@ cmd_bt(void) + break; + + case 'n': +- if (machine_type("X86_64") && STREQ(optarg, "idle")) ++ if ((machine_type("X86_64") || machine_type("ARM64")) && ++ STREQ(optarg, "idle")) + bt->flags |= BT_SKIP_IDLE; + else + option_not_supported(c); +-- +2.30.2 + diff --git a/0008-Remove-ptype-command-from-ps-t-option-to-reduce-memo.patch b/0008-Remove-ptype-command-from-ps-t-option-to-reduce-memo.patch deleted file mode 100644 index ee7a5cd658408e36b7e78b58cbf2826ad3dfc88d..0000000000000000000000000000000000000000 --- a/0008-Remove-ptype-command-from-ps-t-option-to-reduce-memo.patch +++ /dev/null @@ -1,79 +0,0 @@ -From bbd5a5c1f5db3bde04628e75396155260333e53e Mon Sep 17 00:00:00 2001 -From: Kazuhito Hagio -Date: Wed, 19 Jan 2022 16:24:49 +0900 -Subject: [PATCH 08/11] Remove ptype command from "ps -t" option to reduce - memory and time - -With some vmlinux e.g. RHEL9 ones, the first execution of the gdb ptype -command heavily consumes memory and time. The "ps -t" option uses it in -start_time_timespec(), and it can be replaced with the crash macros. - -This can reduce about 1.4 GB memory and 6 seconds time comsumption in -the following test: - - $ echo "ps -t" | time crash vmlinux vmcore - - Without the patch: - 11.60user 0.43system 0:11.94elapsed 100%CPU (0avgtext+0avgdata 1837964maxresident)k - 0inputs+400outputs (0major+413636minor)pagefaults 0swaps - - With the patch: - 5.40user 0.16system 0:05.46elapsed 101%CPU (0avgtext+0avgdata 417896maxresident)k - 0inputs+384outputs (0major+41528minor)pagefaults 0swaps - -Although the ptype command and similar ones cannot be fully removed, -but removing some of them will make the use of crash safer, especially -for an automatic crash reporter. - -Signed-off-by: Kazuhito Hagio -Signed-off-by: Lianbo Jiang ---- - task.c | 25 +++++-------------------- - 1 file changed, 5 insertions(+), 20 deletions(-) - -diff --git a/task.c b/task.c -index 263a8344dd94..a79ed0d96fb5 100644 ---- a/task.c -+++ b/task.c -@@ -4662,8 +4662,6 @@ show_task_times(struct task_context *tcp, ulong flags) - static int - start_time_timespec(void) - { -- char buf[BUFSIZE]; -- - switch(tt->flags & (TIMESPEC | NO_TIMESPEC | START_TIME_NSECS)) - { - case TIMESPEC: -@@ -4677,24 +4675,11 @@ start_time_timespec(void) - - tt->flags |= NO_TIMESPEC; - -- open_tmpfile(); -- sprintf(buf, "ptype struct task_struct"); -- if (!gdb_pass_through(buf, NULL, GNU_RETURN_ON_ERROR)) { -- close_tmpfile(); -- return FALSE; -- } -- -- rewind(pc->tmpfile); -- while (fgets(buf, BUFSIZE, pc->tmpfile)) { -- if (strstr(buf, "start_time;")) { -- if (strstr(buf, "struct timespec")) { -- tt->flags &= ~NO_TIMESPEC; -- tt->flags |= TIMESPEC; -- } -- } -- } -- -- close_tmpfile(); -+ if (VALID_MEMBER(task_struct_start_time) && -+ STREQ(MEMBER_TYPE_NAME("task_struct", "start_time"), "timespec")) { -+ tt->flags &= ~NO_TIMESPEC; -+ tt->flags |= TIMESPEC; -+ } - - if ((tt->flags & NO_TIMESPEC) && (SIZE(task_struct_start_time) == 8)) { - tt->flags &= ~NO_TIMESPEC; --- -2.20.1 - diff --git a/0008-gdb-print-details-of-unnamed-struct-and-union.patch b/0008-gdb-print-details-of-unnamed-struct-and-union.patch new file mode 100644 index 0000000000000000000000000000000000000000..e634e57ba842accbb2526b0eee6531e35d370850 --- /dev/null +++ b/0008-gdb-print-details-of-unnamed-struct-and-union.patch @@ -0,0 +1,66 @@ +From dda5b2d02b8d8de1264f84b6267582aa7a1e5a57 Mon Sep 17 00:00:00 2001 +From: Kazuhito Hagio +Date: Tue, 31 May 2022 17:12:16 +0900 +Subject: [PATCH 08/15] gdb: print details of unnamed struct and union + +Currently gdb's "ptype" command does not print the details of unnamed +structure and union deeper than second level in a structure, it prints +only "{...}" instead. And crash's "struct" and similar commands also +inherit this behavior, so we cannot get the full information of them. + +To print the details of them, change the show variable when it is an +unnamed one like crash-7.x. + +Without the patch: + crash> struct -o page + struct page { + [0] unsigned long flags; + union { + struct {...}; + struct {...}; + ... + +With the patch: + crash> struct -o page + struct page { + [0] unsigned long flags; + union { + struct { + [8] struct list_head lru; + [24] struct address_space *mapping; + [32] unsigned long index; + [40] unsigned long private; + }; + struct { + [8] dma_addr_t dma_addr; + }; + ... + +Signed-off-by: Kazuhito Hagio +--- + gdb-10.2.patch | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/gdb-10.2.patch b/gdb-10.2.patch +index b67db4e1ded9..577f5e45fc5a 100644 +--- a/gdb-10.2.patch ++++ b/gdb-10.2.patch +@@ -1638,3 +1638,15 @@ exit 0 + $(ECHO_CXXLD) $(CC_LD) $(INTERNAL_LDFLAGS) $(WIN32LDAPP) \ + -o $(shell /bin/cat mergeobj) $(LIBGDB_OBS) \ + $(TDEPLIBS) $(TUI_LIBRARY) $(CLIBS) $(LOADLIBES) $(shell /bin/cat mergelibs) ++--- gdb-10.2/gdb/c-typeprint.c.orig +++++ gdb-10.2/gdb/c-typeprint.c ++@@ -1202,6 +1202,9 @@ c_type_print_base_struct_union (struct t ++ = podata->end_bitpos ++ - TYPE_LENGTH (type->field (i).type ()) * TARGET_CHAR_BIT; ++ } +++ else if (strlen(TYPE_FIELD_NAME (type, i)) == 0) +++ /* crash: Print details for unnamed struct and union. */ +++ newshow = show; ++ ++ c_print_type_1 (type->field (i).type (), ++ TYPE_FIELD_NAME (type, i), +-- +2.30.2 + diff --git a/0009-Enhance-dev-d-D-options-to-support-blk-mq-sbitmap.patch b/0009-Enhance-dev-d-D-options-to-support-blk-mq-sbitmap.patch new file mode 100644 index 0000000000000000000000000000000000000000..2280c1f26f138f36b39ce8be00eb0b7fdfe6f187 --- /dev/null +++ b/0009-Enhance-dev-d-D-options-to-support-blk-mq-sbitmap.patch @@ -0,0 +1,392 @@ +From 7095c8fd029e3a33117e3b67de73f504686ebfe2 Mon Sep 17 00:00:00 2001 +From: Lianbo Jiang +Date: Thu, 2 Jun 2022 20:12:55 +0800 +Subject: [PATCH 09/15] Enhance "dev -d|-D" options to support blk-mq sbitmap + +Since Linux 5.16-rc1, which kernel commit 9a14d6ce4135 ("block: remove +debugfs blk_mq_ctx dispatched/merged/completed attributes") removed the +members from struct blk_mq_ctx, crash has not displayed disk I/O statistics +for multiqueue (blk-mq) devices. + +Let's parse the sbitmap in blk-mq layer to support it. + +Signed-off-by: Lianbo Jiang +Signed-off-by: Kazuhito Hagio +--- + defs.h | 11 +++ + dev.c | 244 +++++++++++++++++++++++++++++++++++++++++++++--------- + symbols.c | 22 +++++ + 3 files changed, 238 insertions(+), 39 deletions(-) + +diff --git a/defs.h b/defs.h +index c8444b4e54eb..2681586a33dc 100644 +--- a/defs.h ++++ b/defs.h +@@ -2170,6 +2170,16 @@ struct offset_table { /* stash of commonly-used offsets */ + long sbq_wait_state_wait; + long sbitmap_alloc_hint; + long sbitmap_round_robin; ++ long request_cmd_flags; ++ long request_q; ++ long request_state; ++ long request_queue_queue_hw_ctx; ++ long request_queue_nr_hw_queues; ++ long blk_mq_hw_ctx_tags; ++ long blk_mq_tags_bitmap_tags; ++ long blk_mq_tags_breserved_tags; ++ long blk_mq_tags_nr_reserved_tags; ++ long blk_mq_tags_rqs; + }; + + struct size_table { /* stash of commonly-used sizes */ +@@ -2339,6 +2349,7 @@ struct size_table { /* stash of commonly-used sizes */ + long sbitmap; + long sbitmap_queue; + long sbq_wait_state; ++ long blk_mq_tags; + }; + + struct array_table { +diff --git a/dev.c b/dev.c +index a493e51ac95c..4be4c96df8b0 100644 +--- a/dev.c ++++ b/dev.c +@@ -4238,19 +4238,176 @@ get_one_mctx_diskio(unsigned long mctx, struct diskio *io) + io->write = (dispatch[1] - comp[1]); + } + ++typedef bool (busy_tag_iter_fn)(ulong rq, void *data); ++ ++struct mq_inflight { ++ ulong q; ++ struct diskio *dio; ++}; ++ ++struct bt_iter_data { ++ ulong tags; ++ uint reserved; ++ uint nr_reserved_tags; ++ busy_tag_iter_fn *fn; ++ void *data; ++}; ++ ++/* ++ * See the include/linux/blk_types.h and include/linux/blk-mq.h ++ */ ++#define MQ_RQ_IN_FLIGHT 1 ++#define REQ_OP_BITS 8 ++#define REQ_OP_MASK ((1 << REQ_OP_BITS) - 1) ++ ++static uint op_is_write(uint op) ++{ ++ return (op & REQ_OP_MASK) & 1; ++} ++ ++static bool mq_check_inflight(ulong rq, void *data) ++{ ++ uint cmd_flags = 0, state = 0; ++ ulong addr = 0, queue = 0; ++ struct mq_inflight *mi = data; ++ ++ if (!IS_KVADDR(rq)) ++ return TRUE; ++ ++ addr = rq + OFFSET(request_q); ++ if (!readmem(addr, KVADDR, &queue, sizeof(ulong), "request.q", RETURN_ON_ERROR)) ++ return FALSE; ++ ++ addr = rq + OFFSET(request_cmd_flags); ++ if (!readmem(addr, KVADDR, &cmd_flags, sizeof(uint), "request.cmd_flags", RETURN_ON_ERROR)) ++ return FALSE; ++ ++ addr = rq + OFFSET(request_state); ++ if (!readmem(addr, KVADDR, &state, sizeof(uint), "request.state", RETURN_ON_ERROR)) ++ return FALSE; ++ ++ if (queue == mi->q && state == MQ_RQ_IN_FLIGHT) { ++ if (op_is_write(cmd_flags)) ++ mi->dio->write++; ++ else ++ mi->dio->read++; ++ } ++ ++ return TRUE; ++} ++ ++static bool bt_iter(uint bitnr, void *data) ++{ ++ ulong addr = 0, rqs_addr = 0, rq = 0; ++ struct bt_iter_data *iter_data = data; ++ ulong tag = iter_data->tags; ++ ++ if (!iter_data->reserved) ++ bitnr += iter_data->nr_reserved_tags; ++ ++ /* rqs */ ++ addr = tag + OFFSET(blk_mq_tags_rqs); ++ if (!readmem(addr, KVADDR, &rqs_addr, sizeof(void *), "blk_mq_tags.rqs", RETURN_ON_ERROR)) ++ return FALSE; ++ ++ addr = rqs_addr + bitnr * sizeof(ulong); /* rqs[bitnr] */ ++ if (!readmem(addr, KVADDR, &rq, sizeof(ulong), "blk_mq_tags.rqs[]", RETURN_ON_ERROR)) ++ return FALSE; ++ ++ return iter_data->fn(rq, iter_data->data); ++} ++ ++static void bt_for_each(ulong q, ulong tags, ulong sbq, uint reserved, uint nr_resvd_tags, struct diskio *dio) ++{ ++ struct sbitmap_context sc = {0}; ++ struct mq_inflight mi = { ++ .q = q, ++ .dio = dio, ++ }; ++ struct bt_iter_data iter_data = { ++ .tags = tags, ++ .reserved = reserved, ++ .nr_reserved_tags = nr_resvd_tags, ++ .fn = mq_check_inflight, ++ .data = &mi, ++ }; ++ ++ sbitmap_context_load(sbq + OFFSET(sbitmap_queue_sb), &sc); ++ sbitmap_for_each_set(&sc, bt_iter, &iter_data); ++} ++ ++static void queue_for_each_hw_ctx(ulong q, ulong *hctx, uint cnt, struct diskio *dio) ++{ ++ uint i; ++ ++ for (i = 0; i < cnt; i++) { ++ ulong addr = 0, tags = 0; ++ uint nr_reserved_tags = 0; ++ ++ /* Tags owned by the block driver */ ++ addr = hctx[i] + OFFSET(blk_mq_hw_ctx_tags); ++ if (!readmem(addr, KVADDR, &tags, sizeof(ulong), ++ "blk_mq_hw_ctx.tags", RETURN_ON_ERROR)) ++ break; ++ ++ addr = tags + OFFSET(blk_mq_tags_nr_reserved_tags); ++ if (!readmem(addr, KVADDR, &nr_reserved_tags, sizeof(uint), ++ "blk_mq_tags_nr_reserved_tags", RETURN_ON_ERROR)) ++ break; ++ ++ if (nr_reserved_tags) { ++ addr = tags + OFFSET(blk_mq_tags_breserved_tags); ++ bt_for_each(q, tags, addr, 1, nr_reserved_tags, dio); ++ } ++ addr = tags + OFFSET(blk_mq_tags_bitmap_tags); ++ bt_for_each(q, tags, addr, 0, nr_reserved_tags, dio); ++ } ++} ++ ++static void get_mq_diskio_from_hw_queues(ulong q, struct diskio *dio) ++{ ++ uint cnt = 0; ++ ulong addr = 0, hctx_addr = 0; ++ ulong *hctx_array = NULL; ++ ++ addr = q + OFFSET(request_queue_nr_hw_queues); ++ readmem(addr, KVADDR, &cnt, sizeof(uint), ++ "request_queue.nr_hw_queues", FAULT_ON_ERROR); ++ ++ addr = q + OFFSET(request_queue_queue_hw_ctx); ++ readmem(addr, KVADDR, &hctx_addr, sizeof(void *), ++ "request_queue.queue_hw_ctx", FAULT_ON_ERROR); ++ ++ hctx_array = (ulong *)GETBUF(sizeof(void *) * cnt); ++ if (!hctx_array) ++ error(FATAL, "fail to get memory for the hctx_array\n"); ++ ++ if (!readmem(hctx_addr, KVADDR, hctx_array, sizeof(void *) * cnt, ++ "request_queue.queue_hw_ctx[]", RETURN_ON_ERROR)) { ++ FREEBUF(hctx_array); ++ return; ++ } ++ ++ queue_for_each_hw_ctx(q, hctx_array, cnt, dio); ++ ++ FREEBUF(hctx_array); ++} ++ + static void + get_mq_diskio(unsigned long q, unsigned long *mq_count) + { + int cpu; + unsigned long queue_ctx; + unsigned long mctx_addr; +- struct diskio tmp; ++ struct diskio tmp = {0}; + + if (INVALID_MEMBER(blk_mq_ctx_rq_dispatched) || +- INVALID_MEMBER(blk_mq_ctx_rq_completed)) ++ INVALID_MEMBER(blk_mq_ctx_rq_completed)) { ++ get_mq_diskio_from_hw_queues(q, &tmp); ++ mq_count[0] = tmp.read; ++ mq_count[1] = tmp.write; + return; +- +- memset(&tmp, 0x00, sizeof(struct diskio)); ++ } + + readmem(q + OFFSET(request_queue_queue_ctx), KVADDR, &queue_ctx, + sizeof(ulong), "request_queue.queue_ctx", +@@ -4479,41 +4636,24 @@ display_one_diskio(struct iter *i, unsigned long gendisk, ulong flags) + && (io.read + io.write == 0)) + return; + +- if (use_mq_interface(queue_addr) && +- (INVALID_MEMBER(blk_mq_ctx_rq_dispatched) || +- INVALID_MEMBER(blk_mq_ctx_rq_completed))) +- fprintf(fp, "%s%s%s %s%s%s%s %s%s%s", +- mkstring(buf0, 5, RJUST|INT_DEC, (char *)(unsigned long)major), +- space(MINSPACE), +- mkstring(buf1, VADDR_PRLEN, LJUST|LONG_HEX, (char *)gendisk), +- space(MINSPACE), +- mkstring(buf2, 10, LJUST, disk_name), +- space(MINSPACE), +- mkstring(buf3, VADDR_PRLEN <= 11 ? 11 : VADDR_PRLEN, +- LJUST|LONG_HEX, (char *)queue_addr), +- space(MINSPACE), +- mkstring(buf4, 17, RJUST, "(not supported)"), +- space(MINSPACE)); +- +- else +- fprintf(fp, "%s%s%s %s%s%s%s %s%5d%s%s%s%s%s", +- mkstring(buf0, 5, RJUST|INT_DEC, (char *)(unsigned long)major), +- space(MINSPACE), +- mkstring(buf1, VADDR_PRLEN, LJUST|LONG_HEX, (char *)gendisk), +- space(MINSPACE), +- mkstring(buf2, 10, LJUST, disk_name), +- space(MINSPACE), +- mkstring(buf3, VADDR_PRLEN <= 11 ? 11 : VADDR_PRLEN, +- LJUST|LONG_HEX, (char *)queue_addr), +- space(MINSPACE), +- io.read + io.write, +- space(MINSPACE), +- mkstring(buf4, 5, RJUST|INT_DEC, +- (char *)(unsigned long)io.read), +- space(MINSPACE), +- mkstring(buf5, 5, RJUST|INT_DEC, +- (char *)(unsigned long)io.write), +- space(MINSPACE)); ++ fprintf(fp, "%s%s%s %s%s%s%s %s%5d%s%s%s%s%s", ++ mkstring(buf0, 5, RJUST|INT_DEC, (char *)(unsigned long)major), ++ space(MINSPACE), ++ mkstring(buf1, VADDR_PRLEN, LJUST|LONG_HEX, (char *)gendisk), ++ space(MINSPACE), ++ mkstring(buf2, 10, LJUST, disk_name), ++ space(MINSPACE), ++ mkstring(buf3, VADDR_PRLEN <= 11 ? 11 : VADDR_PRLEN, ++ LJUST|LONG_HEX, (char *)queue_addr), ++ space(MINSPACE), ++ io.read + io.write, ++ space(MINSPACE), ++ mkstring(buf4, 5, RJUST|INT_DEC, ++ (char *)(unsigned long)io.read), ++ space(MINSPACE), ++ mkstring(buf5, 5, RJUST|INT_DEC, ++ (char *)(unsigned long)io.write), ++ space(MINSPACE)); + + if (VALID_MEMBER(request_queue_in_flight)) { + if (!use_mq_interface(queue_addr)) { +@@ -4597,6 +4737,9 @@ void diskio_init(void) + MEMBER_OFFSET_INIT(kobject_entry, "kobject", "entry"); + MEMBER_OFFSET_INIT(kset_list, "kset", "list"); + MEMBER_OFFSET_INIT(request_list_count, "request_list", "count"); ++ MEMBER_OFFSET_INIT(request_cmd_flags, "request", "cmd_flags"); ++ MEMBER_OFFSET_INIT(request_q, "request", "q"); ++ MEMBER_OFFSET_INIT(request_state, "request", "state"); + MEMBER_OFFSET_INIT(request_queue_in_flight, "request_queue", + "in_flight"); + if (MEMBER_EXISTS("request_queue", "rq")) +@@ -4608,10 +4751,33 @@ void diskio_init(void) + "mq_ops"); + ANON_MEMBER_OFFSET_INIT(request_queue_queue_ctx, + "request_queue", "queue_ctx"); ++ MEMBER_OFFSET_INIT(request_queue_queue_hw_ctx, ++ "request_queue", "queue_hw_ctx"); ++ MEMBER_OFFSET_INIT(request_queue_nr_hw_queues, ++ "request_queue", "nr_hw_queues"); + MEMBER_OFFSET_INIT(blk_mq_ctx_rq_dispatched, "blk_mq_ctx", + "rq_dispatched"); + MEMBER_OFFSET_INIT(blk_mq_ctx_rq_completed, "blk_mq_ctx", + "rq_completed"); ++ MEMBER_OFFSET_INIT(blk_mq_hw_ctx_tags, "blk_mq_hw_ctx", "tags"); ++ MEMBER_OFFSET_INIT(blk_mq_tags_bitmap_tags, "blk_mq_tags", ++ "bitmap_tags"); ++ MEMBER_OFFSET_INIT(blk_mq_tags_breserved_tags, "blk_mq_tags", ++ "breserved_tags"); ++ MEMBER_OFFSET_INIT(blk_mq_tags_nr_reserved_tags, "blk_mq_tags", ++ "nr_reserved_tags"); ++ MEMBER_OFFSET_INIT(blk_mq_tags_rqs, "blk_mq_tags", "rqs"); ++ STRUCT_SIZE_INIT(blk_mq_tags, "blk_mq_tags"); ++ STRUCT_SIZE_INIT(sbitmap, "sbitmap"); ++ STRUCT_SIZE_INIT(sbitmap_word, "sbitmap_word"); ++ MEMBER_OFFSET_INIT(sbitmap_word_word, "sbitmap_word", "word"); ++ MEMBER_OFFSET_INIT(sbitmap_word_cleared, "sbitmap_word", "cleared"); ++ MEMBER_OFFSET_INIT(sbitmap_depth, "sbitmap", "depth"); ++ MEMBER_OFFSET_INIT(sbitmap_shift, "sbitmap", "shift"); ++ MEMBER_OFFSET_INIT(sbitmap_map_nr, "sbitmap", "map_nr"); ++ MEMBER_OFFSET_INIT(sbitmap_map, "sbitmap", "map"); ++ MEMBER_OFFSET_INIT(sbitmap_queue_sb, "sbitmap_queue", "sb"); ++ + } + MEMBER_OFFSET_INIT(subsys_private_klist_devices, "subsys_private", + "klist_devices"); +diff --git a/symbols.c b/symbols.c +index 5d12a021c769..c1f09556d710 100644 +--- a/symbols.c ++++ b/symbols.c +@@ -10385,6 +10385,12 @@ dump_offset_table(char *spec, ulong makestruct) + OFFSET(kset_list)); + fprintf(fp, " request_list_count: %ld\n", + OFFSET(request_list_count)); ++ fprintf(fp, " request_cmd_flags: %ld\n", ++ OFFSET(request_cmd_flags)); ++ fprintf(fp, " request_q: %ld\n", ++ OFFSET(request_q)); ++ fprintf(fp, " request_state: %ld\n", ++ OFFSET(request_state)); + fprintf(fp, " request_queue_in_flight: %ld\n", + OFFSET(request_queue_in_flight)); + fprintf(fp, " request_queue_rq: %ld\n", +@@ -10393,10 +10399,25 @@ dump_offset_table(char *spec, ulong makestruct) + OFFSET(request_queue_mq_ops)); + fprintf(fp, " request_queue_queue_ctx: %ld\n", + OFFSET(request_queue_queue_ctx)); ++ fprintf(fp, " request_queue_queue_hw_ctx: %ld\n", ++ OFFSET(request_queue_queue_hw_ctx)); ++ fprintf(fp, " request_queue_nr_hw_queues: %ld\n", ++ OFFSET(request_queue_nr_hw_queues)); + fprintf(fp, " blk_mq_ctx_rq_dispatched: %ld\n", + OFFSET(blk_mq_ctx_rq_dispatched)); + fprintf(fp, " blk_mq_ctx_rq_completed: %ld\n", + OFFSET(blk_mq_ctx_rq_completed)); ++ fprintf(fp, " blk_mq_hw_ctx_tags: %ld\n", ++ OFFSET(blk_mq_hw_ctx_tags)); ++ fprintf(fp, " blk_mq_tags_bitmap_tags: %ld\n", ++ OFFSET(blk_mq_tags_bitmap_tags)); ++ fprintf(fp, " blk_mq_tags_breserved_tags: %ld\n", ++ OFFSET(blk_mq_tags_breserved_tags)); ++ fprintf(fp, " blk_mq_tags_nr_reserved_tags: %ld\n", ++ OFFSET(blk_mq_tags_nr_reserved_tags)); ++ fprintf(fp, " blk_mq_tags_rqs: %ld\n", ++ OFFSET(blk_mq_tags_rqs)); ++ + fprintf(fp, " subsys_private_klist_devices: %ld\n", + OFFSET(subsys_private_klist_devices)); + fprintf(fp, " subsystem_kset: %ld\n", +@@ -11003,6 +11024,7 @@ dump_offset_table(char *spec, ulong makestruct) + fprintf(fp, " sbitmap: %ld\n", SIZE(sbitmap)); + fprintf(fp, " sbitmap_queue: %ld\n", SIZE(sbitmap_queue)); + fprintf(fp, " sbq_wait_state: %ld\n", SIZE(sbq_wait_state)); ++ fprintf(fp, " blk_mq_tags: %ld\n", SIZE(blk_mq_tags)); + + fprintf(fp, "\n array_table:\n"); + /* +-- +2.30.2 + diff --git a/0009-Improve-the-ps-performance-for-vmcores-with-large-nu.patch b/0009-Improve-the-ps-performance-for-vmcores-with-large-nu.patch deleted file mode 100644 index c398eb87889c1c6bd84ed617da980af5565c69c7..0000000000000000000000000000000000000000 --- a/0009-Improve-the-ps-performance-for-vmcores-with-large-nu.patch +++ /dev/null @@ -1,150 +0,0 @@ -From d52cccfaa96ed6f61ff9d53da88715296e31db80 Mon Sep 17 00:00:00 2001 -From: Tao Liu -Date: Fri, 21 Jan 2022 13:43:09 +0800 -Subject: [PATCH 09/11] Improve the ps performance for vmcores with large - number of threads - -Previously, the ps command will iterate over all threads which -have the same tgid, to accumulate their rss value, in order to -get a thread/process's final rss value as part of the final output. - -For non-live systems, the rss accumulation values are identical for -threads which have the same tgid, so there is no need to do the -iteration and accumulation repeatly, thus a lot of readmem calls are -skipped. Otherwise it will be the performance bottleneck if the -vmcores have a large number of threads. - -In this patch, the rss accumulation value will be stored in a cache, -next time a thread with the same tgid will take it directly without -the iteration. - -For example, we can monitor the performance issue when a vmcore has -~65k processes, most of which are threads for several specific -processes. Without the patch, it will take ~7h for ps command -to finish. With the patch, ps command will finish in 1min. - -Signed-off-by: Tao Liu -Signed-off-by: Lianbo Jiang ---- - defs.h | 1 + - memory.c | 70 +++++++++++++++++++++++++++++++------------------------- - task.c | 1 + - 3 files changed, 41 insertions(+), 31 deletions(-) - -diff --git a/defs.h b/defs.h -index 41b6cbc6cc85..77e76f27cddb 100644 ---- a/defs.h -+++ b/defs.h -@@ -830,6 +830,7 @@ struct task_context { /* context stored for each task */ - struct tgid_context { /* tgid and task stored for each task */ - ulong tgid; - ulong task; -+ long rss_cache; - }; - - struct task_table { /* kernel/local task table data */ -diff --git a/memory.c b/memory.c -index 5af45fd7d834..e80c59ea4534 100644 ---- a/memory.c -+++ b/memory.c -@@ -4665,7 +4665,7 @@ void - get_task_mem_usage(ulong task, struct task_mem_usage *tm) - { - struct task_context *tc; -- long rss = 0; -+ long rss = 0, rss_cache = 0; - - BZERO(tm, sizeof(struct task_mem_usage)); - -@@ -4730,38 +4730,46 @@ get_task_mem_usage(ulong task, struct task_mem_usage *tm) - (last->tgid == (last + 1)->tgid)) - last++; - -- while (first <= last) -- { -- /* count 0 -> filepages */ -- if (!readmem(first->task + -- OFFSET(task_struct_rss_stat) + -- OFFSET(task_rss_stat_count), KVADDR, -- &sync_rss, -- sizeof(int), -- "task_struct rss_stat MM_FILEPAGES", -- RETURN_ON_ERROR)) -- continue; -- -- rss += sync_rss; -- -- /* count 1 -> anonpages */ -- if (!readmem(first->task + -- OFFSET(task_struct_rss_stat) + -- OFFSET(task_rss_stat_count) + -- sizeof(int), -- KVADDR, &sync_rss, -- sizeof(int), -- "task_struct rss_stat MM_ANONPAGES", -- RETURN_ON_ERROR)) -- continue; -- -- rss += sync_rss; -- -- if (first == last) -- break; -- first++; -+ /* -+ * Using rss cache for dumpfile is more beneficial than live debug -+ * because its value never changes in dumpfile. -+ */ -+ if (ACTIVE() || last->rss_cache == UNINITIALIZED) { -+ while (first <= last) -+ { -+ /* count 0 -> filepages */ -+ if (!readmem(first->task + -+ OFFSET(task_struct_rss_stat) + -+ OFFSET(task_rss_stat_count), KVADDR, -+ &sync_rss, -+ sizeof(int), -+ "task_struct rss_stat MM_FILEPAGES", -+ RETURN_ON_ERROR)) -+ continue; -+ -+ rss_cache += sync_rss; -+ -+ /* count 1 -> anonpages */ -+ if (!readmem(first->task + -+ OFFSET(task_struct_rss_stat) + -+ OFFSET(task_rss_stat_count) + -+ sizeof(int), -+ KVADDR, &sync_rss, -+ sizeof(int), -+ "task_struct rss_stat MM_ANONPAGES", -+ RETURN_ON_ERROR)) -+ continue; -+ -+ rss_cache += sync_rss; -+ -+ if (first == last) -+ break; -+ first++; -+ } -+ last->rss_cache = rss_cache; - } - -+ rss += last->rss_cache; - tt->last_tgid = last; - } - } -diff --git a/task.c b/task.c -index a79ed0d96fb5..864c838637ee 100644 ---- a/task.c -+++ b/task.c -@@ -2947,6 +2947,7 @@ add_context(ulong task, char *tp) - tg = tt->tgid_array + tt->running_tasks; - tg->tgid = *tgid_addr; - tg->task = task; -+ tg->rss_cache = UNINITIALIZED; - - if (do_verify && !verify_task(tc, do_verify)) { - error(INFO, "invalid task address: %lx\n", tc->task); --- -2.20.1 - diff --git a/0010-Fix-for-dev-d-D-options-to-support-blk-mq-change-on-.patch b/0010-Fix-for-dev-d-D-options-to-support-blk-mq-change-on-.patch new file mode 100644 index 0000000000000000000000000000000000000000..8d5c25b81aed087d89a5f76734a203db5300e465 --- /dev/null +++ b/0010-Fix-for-dev-d-D-options-to-support-blk-mq-change-on-.patch @@ -0,0 +1,121 @@ +From 68ce0b9a35d77d767872dd1a729c50e4695a30a8 Mon Sep 17 00:00:00 2001 +From: Lianbo Jiang +Date: Thu, 2 Jun 2022 20:12:56 +0800 +Subject: [PATCH 10/15] Fix for "dev -d|-D" options to support blk-mq change on + Linux v5.18-rc1 + +Kernel commit 4e5cc99e1e48 ("blk-mq: manage hctx map via xarray") removed +the "queue_hw_ctx" member from struct request_queue at Linux v5.18-rc1, +and replaced it with a struct xarray "hctx_table". Without the patch, the +"dev -d|-D" options will print an error: + + crash> dev -d + MAJOR GENDISK NAME REQUEST_QUEUE TOTAL READ WRITE + + dev: invalid structure member offset: request_queue_queue_hw_ctx + +With the patch: + crash> dev -d + MAJOR GENDISK NAME REQUEST_QUEUE TOTAL READ WRITE + 8 ffff8e99d0a1ae00 sda ffff8e9c14c59980 10 6 4 + +Signed-off-by: Lianbo Jiang +--- + defs.h | 1 + + dev.c | 42 +++++++++++++++++++++++++++++++++--------- + symbols.c | 2 ++ + 3 files changed, 36 insertions(+), 9 deletions(-) + +diff --git a/defs.h b/defs.h +index 2681586a33dc..7d3b73422f48 100644 +--- a/defs.h ++++ b/defs.h +@@ -2180,6 +2180,7 @@ struct offset_table { /* stash of commonly-used offsets */ + long blk_mq_tags_breserved_tags; + long blk_mq_tags_nr_reserved_tags; + long blk_mq_tags_rqs; ++ long request_queue_hctx_table; + }; + + struct size_table { /* stash of commonly-used sizes */ +diff --git a/dev.c b/dev.c +index 4be4c96df8b0..0172c83ffaea 100644 +--- a/dev.c ++++ b/dev.c +@@ -4369,20 +4369,42 @@ static void get_mq_diskio_from_hw_queues(ulong q, struct diskio *dio) + uint cnt = 0; + ulong addr = 0, hctx_addr = 0; + ulong *hctx_array = NULL; ++ struct list_pair *lp = NULL; ++ ++ if (VALID_MEMBER(request_queue_hctx_table)) { ++ addr = q + OFFSET(request_queue_hctx_table); ++ cnt = do_xarray(addr, XARRAY_COUNT, NULL); ++ lp = (struct list_pair *)GETBUF(sizeof(struct list_pair) * (cnt + 1)); ++ if (!lp) ++ error(FATAL, "fail to get memory for list_pair.\n"); ++ lp[0].index = cnt; ++ cnt = do_xarray(addr, XARRAY_GATHER, lp); ++ } else { ++ addr = q + OFFSET(request_queue_nr_hw_queues); ++ readmem(addr, KVADDR, &cnt, sizeof(uint), ++ "request_queue.nr_hw_queues", FAULT_ON_ERROR); + +- addr = q + OFFSET(request_queue_nr_hw_queues); +- readmem(addr, KVADDR, &cnt, sizeof(uint), +- "request_queue.nr_hw_queues", FAULT_ON_ERROR); +- +- addr = q + OFFSET(request_queue_queue_hw_ctx); +- readmem(addr, KVADDR, &hctx_addr, sizeof(void *), +- "request_queue.queue_hw_ctx", FAULT_ON_ERROR); ++ addr = q + OFFSET(request_queue_queue_hw_ctx); ++ readmem(addr, KVADDR, &hctx_addr, sizeof(void *), ++ "request_queue.queue_hw_ctx", FAULT_ON_ERROR); ++ } + + hctx_array = (ulong *)GETBUF(sizeof(void *) * cnt); +- if (!hctx_array) ++ if (!hctx_array) { ++ if (lp) ++ FREEBUF(lp); + error(FATAL, "fail to get memory for the hctx_array\n"); ++ } ++ ++ if (lp && hctx_array) { ++ uint i; ++ ++ /* copy it from list_pair to hctx_array */ ++ for (i = 0; i < cnt; i++) ++ hctx_array[i] = (ulong)lp[i].value; + +- if (!readmem(hctx_addr, KVADDR, hctx_array, sizeof(void *) * cnt, ++ FREEBUF(lp); ++ } else if (!readmem(hctx_addr, KVADDR, hctx_array, sizeof(void *) * cnt, + "request_queue.queue_hw_ctx[]", RETURN_ON_ERROR)) { + FREEBUF(hctx_array); + return; +@@ -4755,6 +4777,8 @@ void diskio_init(void) + "request_queue", "queue_hw_ctx"); + MEMBER_OFFSET_INIT(request_queue_nr_hw_queues, + "request_queue", "nr_hw_queues"); ++ MEMBER_OFFSET_INIT(request_queue_hctx_table, ++ "request_queue", "hctx_table"); + MEMBER_OFFSET_INIT(blk_mq_ctx_rq_dispatched, "blk_mq_ctx", + "rq_dispatched"); + MEMBER_OFFSET_INIT(blk_mq_ctx_rq_completed, "blk_mq_ctx", +diff --git a/symbols.c b/symbols.c +index c1f09556d710..bee1faf92c83 100644 +--- a/symbols.c ++++ b/symbols.c +@@ -10403,6 +10403,8 @@ dump_offset_table(char *spec, ulong makestruct) + OFFSET(request_queue_queue_hw_ctx)); + fprintf(fp, " request_queue_nr_hw_queues: %ld\n", + OFFSET(request_queue_nr_hw_queues)); ++ fprintf(fp, " request_queue_hctx_table: %ld\n", ++ OFFSET(request_queue_hctx_table)); + fprintf(fp, " blk_mq_ctx_rq_dispatched: %ld\n", + OFFSET(blk_mq_ctx_rq_dispatched)); + fprintf(fp, " blk_mq_ctx_rq_completed: %ld\n", +-- +2.30.2 + diff --git a/0010-arm64-Fix-segfault-by-bt-command-with-offline-cpus.patch b/0010-arm64-Fix-segfault-by-bt-command-with-offline-cpus.patch deleted file mode 100644 index 1c4040fc622347a7b0b0639d45a733bd10a83089..0000000000000000000000000000000000000000 --- a/0010-arm64-Fix-segfault-by-bt-command-with-offline-cpus.patch +++ /dev/null @@ -1,59 +0,0 @@ -From 1a1fd21c625cb2ca335e626eb50426f13c4160f7 Mon Sep 17 00:00:00 2001 -From: Kazuhito Hagio -Date: Wed, 26 Jan 2022 06:07:00 +0000 -Subject: [PATCH 10/11] arm64: Fix segfault by "bt" command with offline cpus - -Currently on arm64, NT_PRSTATUS notes in dumpfile are not mapped to -online cpus and machine_specific->panic_task_regs correctly. As a -result, the "bt" command can cause a segmentation fault. - - crash> bt -c 0 - PID: 0 TASK: ffff8000117fa240 CPU: 0 COMMAND: "swapper/0" - Segmentation fault (core dumped) - -To fix this, -1) make map_cpus_to_prstatus_kdump_cmprs() map the notes to - dd->nt_prstatus_percpu also on arm64, and -2) move arm64_get_crash_notes() to machdep_init(POST_INIT) in order - to apply the mapping to machine_specific->panic_task_regs. - -Resolves: https://github.com/crash-utility/crash/issues/105 -Reported-by: xuchunmei000 -Signed-off-by: Kazuhito Hagio -Tested-by: David Wysochanski -Signed-off-by: Lianbo Jiang ---- - arm64.c | 2 +- - diskdump.c | 3 +-- - 2 files changed, 2 insertions(+), 3 deletions(-) - -diff --git a/arm64.c b/arm64.c -index 23c3d75d85aa..4f2c2b5104a1 100644 ---- a/arm64.c -+++ b/arm64.c -@@ -472,7 +472,7 @@ arm64_init(int when) - arm64_stackframe_init(); - break; - -- case POST_VM: -+ case POST_INIT: - /* - * crash_notes contains machine specific information about the - * crash. In particular, it contains CPU registers at the time -diff --git a/diskdump.c b/diskdump.c -index 112f769f8949..690b42443ed2 100644 ---- a/diskdump.c -+++ b/diskdump.c -@@ -111,8 +111,7 @@ map_cpus_to_prstatus_kdump_cmprs(void) - if (pc->flags2 & QEMU_MEM_DUMP_COMPRESSED) /* notes exist for all cpus */ - goto resize_note_pointers; - -- if (!(online = get_cpus_online()) || (online == kt->cpus) || -- machine_type("ARM64")) -+ if (!(online = get_cpus_online()) || (online == kt->cpus)) - goto resize_note_pointers; - - if (CRASHDEBUG(1)) --- -2.20.1 - diff --git a/0011-Doc-update-man-page-for-the-bpf-and-sbitmapq-command.patch b/0011-Doc-update-man-page-for-the-bpf-and-sbitmapq-command.patch new file mode 100644 index 0000000000000000000000000000000000000000..938e58d39c1925609455ae2172666ff5c1397c18 --- /dev/null +++ b/0011-Doc-update-man-page-for-the-bpf-and-sbitmapq-command.patch @@ -0,0 +1,43 @@ +From c672d7a4c290712b32c54329cbdc1e74d122e813 Mon Sep 17 00:00:00 2001 +From: Lianbo Jiang +Date: Mon, 6 Jun 2022 19:09:16 +0800 +Subject: [PATCH 11/15] Doc: update man page for the "bpf" and "sbitmapq" + commands + +The information of the "bpf" and "sbitmapq" commands is missing in the man +page of the crash utility. Let's add it to the man page. + +Signed-off-by: Lianbo Jiang +--- + crash.8 | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/crash.8 b/crash.8 +index 1f3657b11e4c..e553a0b4adb3 100644 +--- a/crash.8 ++++ b/crash.8 +@@ -584,6 +584,9 @@ creates a single-word alias for a command. + .I ascii + displays an ascii chart or translates a numeric value into its ascii components. + .TP ++.I bpf ++provides information on currently-loaded eBPF programs and maps. ++.TP + .I bt + displays a task's kernel-stack backtrace. If it is given the + .I \-a +@@ -706,6 +709,11 @@ number of seconds between each command execution. + .I runq + displays the tasks on the run queue. + .TP ++.I sbitmapq ++dumps the contents of the sbitmap_queue structure and the used ++bits in the bitmap. Also, it shows the dump of a structure array ++associated with the sbitmap_queue. ++.TP + .I search + searches a range of user or kernel memory space for given value. + .TP +-- +2.30.2 + diff --git a/0011-Fix-for-kmem-s-S-and-bt-F-F-on-Linux-5.17-rc1.patch b/0011-Fix-for-kmem-s-S-and-bt-F-F-on-Linux-5.17-rc1.patch deleted file mode 100644 index 1bd6774ee3741d9a10cfa4a2757921966a1acef3..0000000000000000000000000000000000000000 --- a/0011-Fix-for-kmem-s-S-and-bt-F-F-on-Linux-5.17-rc1.patch +++ /dev/null @@ -1,89 +0,0 @@ -From 86446eaba408807e00cf2310d5748aa6b7511284 Mon Sep 17 00:00:00 2001 -From: Kazuhito Hagio -Date: Wed, 2 Feb 2022 02:14:56 +0000 -Subject: [PATCH 11/11] Fix for "kmem -s|-S" and "bt -F[F]" on Linux 5.17-rc1 - -Since the following kernel commits split slab info from struct page -into struct slab, crash cannot get several slab related offsets from -struct page. - - d122019bf061 ("mm: Split slab into its own type") - 07f910f9b729 ("mm: Remove slab from struct page") - -Without the patch, "kmem -s|-S" and "bt -F[F]" options cannot work -correctly with the following errors: - - crash> kmem -s kmem_cache - CACHE OBJSIZE ALLOCATED TOTAL SLABS SSIZE NAME - kmem: page_to_nid: invalid page: ffff9454afc35020 - kmem: kmem_cache: cannot gather relevant slab data - ffff945140042000 216 ? ? ? 8k kmem_cache - - crash> bt -F - ... - bt: invalid structure member offset: page_slab - FILE: memory.c LINE: 9477 FUNCTION: vaddr_to_kmem_cache() - -Signed-by: Kazuhito Hagio -Signed-off-by: Lianbo Jiang ---- - memory.c | 13 +++++++++++++ - 1 file changed, 13 insertions(+) - -diff --git a/memory.c b/memory.c -index e80c59ea4534..8448ddc3a16c 100644 ---- a/memory.c -+++ b/memory.c -@@ -421,6 +421,8 @@ vm_init(void) - MEMBER_OFFSET_INIT(page_prev, "page", "prev"); - if (INVALID_MEMBER(page_next)) - ANON_MEMBER_OFFSET_INIT(page_next, "page", "next"); -+ if (INVALID_MEMBER(page_next)) -+ MEMBER_OFFSET_INIT(page_next, "slab", "next"); - - MEMBER_OFFSET_INIT(page_list, "page", "list"); - if (VALID_MEMBER(page_list)) { -@@ -747,11 +749,15 @@ vm_init(void) - MEMBER_OFFSET_INIT(kmem_cache_random, "kmem_cache", "random"); - MEMBER_OFFSET_INIT(kmem_cache_cpu_freelist, "kmem_cache_cpu", "freelist"); - MEMBER_OFFSET_INIT(kmem_cache_cpu_page, "kmem_cache_cpu", "page"); -+ if (INVALID_MEMBER(kmem_cache_cpu_page)) -+ MEMBER_OFFSET_INIT(kmem_cache_cpu_page, "kmem_cache_cpu", "slab"); - MEMBER_OFFSET_INIT(kmem_cache_cpu_node, "kmem_cache_cpu", "node"); - MEMBER_OFFSET_INIT(kmem_cache_cpu_partial, "kmem_cache_cpu", "partial"); - MEMBER_OFFSET_INIT(page_inuse, "page", "inuse"); - if (INVALID_MEMBER(page_inuse)) - ANON_MEMBER_OFFSET_INIT(page_inuse, "page", "inuse"); -+ if (INVALID_MEMBER(page_inuse)) -+ MEMBER_OFFSET_INIT(page_inuse, "slab", "inuse"); - MEMBER_OFFSET_INIT(page_offset, "page", "offset"); - if (INVALID_MEMBER(page_offset)) - ANON_MEMBER_OFFSET_INIT(page_offset, "page", "offset"); -@@ -763,6 +769,9 @@ vm_init(void) - if (INVALID_MEMBER(page_slab)) - ANON_MEMBER_OFFSET_INIT(page_slab, "page", "slab_cache"); - } -+ if (INVALID_MEMBER(page_slab)) -+ MEMBER_OFFSET_INIT(page_slab, "slab", "slab_cache"); -+ - MEMBER_OFFSET_INIT(page_slab_page, "page", "slab_page"); - if (INVALID_MEMBER(page_slab_page)) - ANON_MEMBER_OFFSET_INIT(page_slab_page, "page", "slab_page"); -@@ -772,10 +781,14 @@ vm_init(void) - MEMBER_OFFSET_INIT(page_freelist, "page", "freelist"); - if (INVALID_MEMBER(page_freelist)) - ANON_MEMBER_OFFSET_INIT(page_freelist, "page", "freelist"); -+ if (INVALID_MEMBER(page_freelist)) -+ MEMBER_OFFSET_INIT(page_freelist, "slab", "freelist"); - if (INVALID_MEMBER(kmem_cache_objects)) { - MEMBER_OFFSET_INIT(kmem_cache_oo, "kmem_cache", "oo"); - /* NOTE: returns offset of containing bitfield */ - ANON_MEMBER_OFFSET_INIT(page_objects, "page", "objects"); -+ if (INVALID_MEMBER(page_objects)) -+ ANON_MEMBER_OFFSET_INIT(page_objects, "slab", "objects"); - } - if (VALID_MEMBER(kmem_cache_node)) { - ARRAY_LENGTH_INIT(len, NULL, "kmem_cache.node", NULL, 0); --- -2.20.1 - diff --git a/0012-sbitmapq-Fix-for-sbitmap_queue-without-ws_active-mem.patch b/0012-sbitmapq-Fix-for-sbitmap_queue-without-ws_active-mem.patch new file mode 100644 index 0000000000000000000000000000000000000000..2faa56d5924bdf55e0cf9850de4eb5df89c98bfb --- /dev/null +++ b/0012-sbitmapq-Fix-for-sbitmap_queue-without-ws_active-mem.patch @@ -0,0 +1,47 @@ +From 9ce31a14d1083cbb2beb4a8e6eb7b88234b79a99 Mon Sep 17 00:00:00 2001 +From: Kazuhito Hagio +Date: Fri, 10 Jun 2022 11:49:47 +0900 +Subject: [PATCH 12/15] sbitmapq: Fix for sbitmap_queue without ws_active + member + +The sbitmap_queue.ws_active member was added by kernel commit 5d2ee7122c73 +("sbitmap: optimize wakeup check") at Linux 5.0. Without the patch, on +earlier kernels the "sbitmapq" command fails with the following error: + + crash> sbitmapq ffff8f1a3611cf10 + + sbitmapq: invalid structure member offset: sbitmap_queue_ws_active + FILE: sbitmap.c LINE: 393 FUNCTION: sbitmap_queue_context_load() + +Signed-off-by: Kazuhito Hagio +--- + sbitmap.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/sbitmap.c b/sbitmap.c +index e8ebd62fe01c..152c28e6875f 100644 +--- a/sbitmap.c ++++ b/sbitmap.c +@@ -325,7 +325,8 @@ static void sbitmap_queue_show(const struct sbitmap_queue_context *sqc, + + fprintf(fp, "wake_batch = %u\n", sqc->wake_batch); + fprintf(fp, "wake_index = %d\n", sqc->wake_index); +- fprintf(fp, "ws_active = %d\n", sqc->ws_active); ++ if (VALID_MEMBER(sbitmap_queue_ws_active)) /* 5.0 and later */ ++ fprintf(fp, "ws_active = %d\n", sqc->ws_active); + + sbq_wait_state_size = SIZE(sbq_wait_state); + wait_cnt_off = OFFSET(sbq_wait_state_wait_cnt); +@@ -380,7 +381,8 @@ static void sbitmap_queue_context_load(ulong addr, struct sbitmap_queue_context + sqc->wake_batch = UINT(sbitmap_queue_buf + OFFSET(sbitmap_queue_wake_batch)); + sqc->wake_index = INT(sbitmap_queue_buf + OFFSET(sbitmap_queue_wake_index)); + sqc->ws_addr = ULONG(sbitmap_queue_buf + OFFSET(sbitmap_queue_ws)); +- sqc->ws_active = INT(sbitmap_queue_buf + OFFSET(sbitmap_queue_ws_active)); ++ if (VALID_MEMBER(sbitmap_queue_ws_active)) ++ sqc->ws_active = INT(sbitmap_queue_buf + OFFSET(sbitmap_queue_ws_active)); + if (VALID_MEMBER(sbitmap_queue_round_robin)) + sqc->round_robin = BOOL(sbitmap_queue_buf + OFFSET(sbitmap_queue_round_robin)); + sqc->min_shallow_depth = UINT(sbitmap_queue_buf + OFFSET(sbitmap_queue_min_shallow_depth)); +-- +2.30.2 + diff --git a/0013-sbitmapq-Fix-for-sbitmap_word-without-cleared-member.patch b/0013-sbitmapq-Fix-for-sbitmap_word-without-cleared-member.patch new file mode 100644 index 0000000000000000000000000000000000000000..e3d739610b9819dc007c3c45a269991f5775aef4 --- /dev/null +++ b/0013-sbitmapq-Fix-for-sbitmap_word-without-cleared-member.patch @@ -0,0 +1,109 @@ +From 0d3e86fee5eead93b521a0e20a0e099ede4ab72b Mon Sep 17 00:00:00 2001 +From: Kazuhito Hagio +Date: Fri, 10 Jun 2022 11:49:47 +0900 +Subject: [PATCH 13/15] sbitmapq: Fix for sbitmap_word without cleared member + +The sbitmap_word.cleared member was added by kernel commit ea86ea2cdced +("sbitmap: ammortize cost of clearing bits") at Linux 5.0. Without the +patch, on earlier kernels the "sbitmapq" command fails with the +following error: + + crash> sbitmapq ffff8f1a3611cf10 + + sbitmapq: invalid structure member offset: sbitmap_word_cleared + FILE: sbitmap.c LINE: 92 FUNCTION: __sbitmap_weight() + +Signed-off-by: Kazuhito Hagio +--- + sbitmap.c | 26 ++++++++++++++++++-------- + 1 file changed, 18 insertions(+), 8 deletions(-) + +diff --git a/sbitmap.c b/sbitmap.c +index 152c28e6875f..c9f7209f9e3e 100644 +--- a/sbitmap.c ++++ b/sbitmap.c +@@ -89,7 +89,6 @@ static unsigned int __sbitmap_weight(const struct sbitmap_context *sc, bool set) + { + const ulong sbitmap_word_size = SIZE(sbitmap_word); + const ulong w_word_off = OFFSET(sbitmap_word_word); +- const ulong w_cleared_off = OFFSET(sbitmap_word_cleared); + + unsigned int weight = 0; + ulong addr = sc->map_addr; +@@ -111,7 +110,10 @@ static unsigned int __sbitmap_weight(const struct sbitmap_context *sc, bool set) + word = ULONG(sbitmap_word_buf + w_word_off); + weight += bitmap_weight(word, depth); + } else { +- cleared = ULONG(sbitmap_word_buf + w_cleared_off); ++ if (VALID_MEMBER(sbitmap_word_cleared)) ++ cleared = ULONG(sbitmap_word_buf + OFFSET(sbitmap_word_cleared)); ++ else ++ cleared = 0; + weight += bitmap_weight(cleared, depth); + } + +@@ -130,7 +132,10 @@ static unsigned int sbitmap_weight(const struct sbitmap_context *sc) + + static unsigned int sbitmap_cleared(const struct sbitmap_context *sc) + { +- return __sbitmap_weight(sc, false); ++ if (VALID_MEMBER(sbitmap_word_cleared)) /* 5.0 and later */ ++ return __sbitmap_weight(sc, false); ++ ++ return 0; + } + + static void sbitmap_emit_byte(unsigned int offset, uint8_t byte) +@@ -149,7 +154,6 @@ static void sbitmap_bitmap_show(const struct sbitmap_context *sc) + { + const ulong sbitmap_word_size = SIZE(sbitmap_word); + const ulong w_word_off = OFFSET(sbitmap_word_word); +- const ulong w_cleared_off = OFFSET(sbitmap_word_cleared); + + uint8_t byte = 0; + unsigned int byte_bits = 0; +@@ -169,7 +173,10 @@ static void sbitmap_bitmap_show(const struct sbitmap_context *sc) + } + + word = ULONG(sbitmap_word_buf + w_word_off); +- cleared = ULONG(sbitmap_word_buf + w_cleared_off); ++ if (VALID_MEMBER(sbitmap_word_cleared)) ++ cleared = ULONG(sbitmap_word_buf + OFFSET(sbitmap_word_cleared)); ++ else ++ cleared = 0; + word_bits = __map_depth(sc, i); + + word &= ~cleared; +@@ -219,7 +226,6 @@ static void __sbitmap_for_each_set(const struct sbitmap_context *sc, + { + const ulong sbitmap_word_size = SIZE(sbitmap_word); + const ulong w_word_off = OFFSET(sbitmap_word_word); +- const ulong w_cleared_off = OFFSET(sbitmap_word_cleared); + + unsigned int index; + unsigned int nr; +@@ -245,7 +251,10 @@ static void __sbitmap_for_each_set(const struct sbitmap_context *sc, + } + + w_word = ULONG(sbitmap_word_buf + w_word_off); +- w_cleared = ULONG(sbitmap_word_buf + w_cleared_off); ++ if (VALID_MEMBER(sbitmap_word_cleared)) ++ w_cleared = ULONG(sbitmap_word_buf + OFFSET(sbitmap_word_cleared)); ++ else ++ w_cleared = 0; + + depth = min(__map_depth(sc, index) - nr, sc->depth - scanned); + +@@ -297,7 +306,8 @@ static void sbitmap_queue_show(const struct sbitmap_queue_context *sqc, + + fprintf(fp, "depth = %u\n", sc->depth); + fprintf(fp, "busy = %u\n", sbitmap_weight(sc) - sbitmap_cleared(sc)); +- fprintf(fp, "cleared = %u\n", sbitmap_cleared(sc)); ++ if (VALID_MEMBER(sbitmap_word_cleared)) /* 5.0 and later */ ++ fprintf(fp, "cleared = %u\n", sbitmap_cleared(sc)); + fprintf(fp, "bits_per_word = %u\n", 1U << sc->shift); + fprintf(fp, "map_nr = %u\n", sc->map_nr); + +-- +2.30.2 + diff --git a/0014-sbitmapq-Fix-for-sbitmap_queue-without-min_shallow_d.patch b/0014-sbitmapq-Fix-for-sbitmap_queue-without-min_shallow_d.patch new file mode 100644 index 0000000000000000000000000000000000000000..49a6848c0ea667418c6c71cb90a9fb62967cbba2 --- /dev/null +++ b/0014-sbitmapq-Fix-for-sbitmap_queue-without-min_shallow_d.patch @@ -0,0 +1,48 @@ +From 12fe6c7cdd768f87ce6e903a2bbfb0c0591585c5 Mon Sep 17 00:00:00 2001 +From: Kazuhito Hagio +Date: Fri, 10 Jun 2022 11:49:47 +0900 +Subject: [PATCH 14/15] sbitmapq: Fix for sbitmap_queue without + min_shallow_depth member + +The sbitmap_queue.min_shallow_depth member was added by kernel commit +a327553965de ("sbitmap: fix missed wakeups caused by sbitmap_queue_get_shallow()") +at Linux 4.18. Without the patch, on earlier kernels the "sbitmapq" +command fails with the following error: + + crash> sbitmapq ffff89bb7638ee50 + + sbitmapq: invalid structure member offset: sbitmap_queue_min_shallow_depth + FILE: sbitmap.c LINE: 398 FUNCTION: sbitmap_queue_context_load() + +Signed-off-by: Kazuhito Hagio +--- + sbitmap.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/sbitmap.c b/sbitmap.c +index c9f7209f9e3e..bb2f19e6207b 100644 +--- a/sbitmap.c ++++ b/sbitmap.c +@@ -371,7 +371,8 @@ static void sbitmap_queue_show(const struct sbitmap_queue_context *sqc, + else if (VALID_MEMBER(sbitmap_round_robin)) /* 5.13 and later */ + fprintf(fp, "round_robin = %d\n", sc->round_robin); + +- fprintf(fp, "min_shallow_depth = %u\n", sqc->min_shallow_depth); ++ if (VALID_MEMBER(sbitmap_queue_min_shallow_depth)) /* 4.18 and later */ ++ fprintf(fp, "min_shallow_depth = %u\n", sqc->min_shallow_depth); + } + + static void sbitmap_queue_context_load(ulong addr, struct sbitmap_queue_context *sqc) +@@ -395,7 +396,8 @@ static void sbitmap_queue_context_load(ulong addr, struct sbitmap_queue_context + sqc->ws_active = INT(sbitmap_queue_buf + OFFSET(sbitmap_queue_ws_active)); + if (VALID_MEMBER(sbitmap_queue_round_robin)) + sqc->round_robin = BOOL(sbitmap_queue_buf + OFFSET(sbitmap_queue_round_robin)); +- sqc->min_shallow_depth = UINT(sbitmap_queue_buf + OFFSET(sbitmap_queue_min_shallow_depth)); ++ if (VALID_MEMBER(sbitmap_queue_min_shallow_depth)) ++ sqc->min_shallow_depth = UINT(sbitmap_queue_buf + OFFSET(sbitmap_queue_min_shallow_depth)); + + FREEBUF(sbitmap_queue_buf); + } +-- +2.30.2 + diff --git a/0015-Make-dev-d-D-options-parse-sbitmap-on-Linux-4.18-and.patch b/0015-Make-dev-d-D-options-parse-sbitmap-on-Linux-4.18-and.patch new file mode 100644 index 0000000000000000000000000000000000000000..181053909039b64aa1030166d22fb4cb3926a053 --- /dev/null +++ b/0015-Make-dev-d-D-options-parse-sbitmap-on-Linux-4.18-and.patch @@ -0,0 +1,83 @@ +From c07068266b41450ca6821ee0a1a3adf34206015f Mon Sep 17 00:00:00 2001 +From: Kazuhito Hagio +Date: Fri, 10 Jun 2022 15:21:53 +0900 +Subject: [PATCH 15/15] Make "dev -d|-D" options parse sbitmap on Linux 4.18 + and later + +There have been a few reports that the "dev -d|-D" options displayed +incorrect I/O stats due to racy blk_mq_ctx.rq_* counters. To fix it, +make the options parse sbitmap to count I/O stats on Linux 4.18 and +later kernels, which include RHEL8 ones. + +To do this, adjust to the blk_mq_tags structure of Linux 5.10 through +5.15 kernels, which contain kernel commit 222a5ae03cdd ("blk-mq: Use +pointers for blk_mq_tags bitmap tags") and do not contain ae0f1a732f4a +("blk-mq: Stop using pointers for blk_mq_tags bitmap tags"). + +Signed-off-by: Kazuhito Hagio +--- + dev.c | 25 +++++++++++++++++++++++-- + 1 file changed, 23 insertions(+), 2 deletions(-) + +diff --git a/dev.c b/dev.c +index 0172c83ffaea..db97f8aebdc2 100644 +--- a/dev.c ++++ b/dev.c +@@ -4339,6 +4339,10 @@ static void bt_for_each(ulong q, ulong tags, ulong sbq, uint reserved, uint nr_r + static void queue_for_each_hw_ctx(ulong q, ulong *hctx, uint cnt, struct diskio *dio) + { + uint i; ++ int bitmap_tags_is_ptr = 0; ++ ++ if (MEMBER_TYPE("blk_mq_tags", "bitmap_tags") == TYPE_CODE_PTR) ++ bitmap_tags_is_ptr = 1; + + for (i = 0; i < cnt; i++) { + ulong addr = 0, tags = 0; +@@ -4357,9 +4361,17 @@ static void queue_for_each_hw_ctx(ulong q, ulong *hctx, uint cnt, struct diskio + + if (nr_reserved_tags) { + addr = tags + OFFSET(blk_mq_tags_breserved_tags); ++ if (bitmap_tags_is_ptr && ++ !readmem(addr, KVADDR, &addr, sizeof(ulong), ++ "blk_mq_tags.bitmap_tags", RETURN_ON_ERROR)) ++ break; + bt_for_each(q, tags, addr, 1, nr_reserved_tags, dio); + } + addr = tags + OFFSET(blk_mq_tags_bitmap_tags); ++ if (bitmap_tags_is_ptr && ++ !readmem(addr, KVADDR, &addr, sizeof(ulong), ++ "blk_mq_tags.bitmap_tags", RETURN_ON_ERROR)) ++ break; + bt_for_each(q, tags, addr, 0, nr_reserved_tags, dio); + } + } +@@ -4423,14 +4435,23 @@ get_mq_diskio(unsigned long q, unsigned long *mq_count) + unsigned long mctx_addr; + struct diskio tmp = {0}; + +- if (INVALID_MEMBER(blk_mq_ctx_rq_dispatched) || +- INVALID_MEMBER(blk_mq_ctx_rq_completed)) { ++ /* ++ * Currently this function does not support old blk-mq implementation ++ * before 12f5b9314545 ("blk-mq: Remove generation seqeunce"), so ++ * filter them out. ++ */ ++ if (VALID_MEMBER(request_state)) { ++ if (CRASHDEBUG(1)) ++ fprintf(fp, "mq: using sbitmap\n"); + get_mq_diskio_from_hw_queues(q, &tmp); + mq_count[0] = tmp.read; + mq_count[1] = tmp.write; + return; + } + ++ if (CRASHDEBUG(1)) ++ fprintf(fp, "mq: using blk_mq_ctx.rq_{completed,dispatched} counters\n"); ++ + readmem(q + OFFSET(request_queue_queue_ctx), KVADDR, &queue_ctx, + sizeof(ulong), "request_queue.queue_ctx", + FAULT_ON_ERROR); +-- +2.30.2 + diff --git a/crash-8.0.1.tar.gz b/crash-8.0.1.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..af2ced0ca2118b41e5dde7a3c8309b4f9e58432e Binary files /dev/null and b/crash-8.0.1.tar.gz differ diff --git a/rhel8_build.patch b/crash-8.0.1_build.patch similarity index 76% rename from rhel8_build.patch rename to crash-8.0.1_build.patch index 55560b8278bc9ccff547749ab78b55e38883f2e0..284566273addde676b37e8f3d384347986af25f2 100644 --- a/rhel8_build.patch +++ b/crash-8.0.1_build.patch @@ -1,6 +1,6 @@ ---- crash-7.3.1/Makefile.orig -+++ crash-7.3.1/Makefile -@@ -200,7 +200,7 @@ GDB_FLAGS= +--- crash-8.0.1/Makefile.orig ++++ crash-8.0.1/Makefile +@@ -204,7 +204,7 @@ GDB_FLAGS= # TARGET_CFLAGS will be configured automatically by configure TARGET_CFLAGS= @@ -9,18 +9,18 @@ GPL_FILES= TAR_FILES=${SOURCE_FILES} Makefile ${GPL_FILES} README .rh_rpm_package crash.8 \ -@@ -230,7 +230,7 @@ all: make_configure +@@ -256,7 +256,7 @@ all: make_configure gdb_merge: force @if [ ! -f ${GDB}/README ]; then \ - make --no-print-directory gdb_unzip; fi + $(MAKE) gdb_unzip; fi - @echo "${LDFLAGS} -lz -llzo2 -lsnappy -lzstd -ldl -rdynamic" > ${GDB}/gdb/mergelibs -+ @echo "${LDFLAGS} -lz -llzo2 -lsnappy -lzstd -ldl -rdynamic -Wl,-z,now -fpie" > ${GDB}/gdb/mergelibs ++ @echo "${LDFLAGS} -lz -llzo2 -lsnappy -lzstd -ldl -rdynamic -Wl,-z,now -fPIE" > ${GDB}/gdb/mergelibs @echo "../../${PROGRAM} ../../${PROGRAM}lib.a" > ${GDB}/gdb/mergeobj @rm -f ${PROGRAM} @if [ ! -f ${GDB}/config.status ]; then \ ---- crash-7.3.1/configure.c.orig -+++ crash-7.3.1/configure.c -@@ -800,7 +800,8 @@ build_configure(struct supported_gdb_version *sp) +--- crash-8.0.1/configure.c.orig ++++ crash-8.0.1/configure.c +@@ -810,7 +810,8 @@ build_configure(struct supported_gdb_version *sp) fprintf(fp2, "%s\n", sp->GDB); sprintf(target_data.gdb_version, "%s", &sp->GDB[4]); } else if (strncmp(buf, "LDFLAGS=", strlen("LDFLAGS=")) == 0) { @@ -30,3 +30,4 @@ } else fprintf(fp2, "%s", buf); + diff --git a/crash.spec b/crash.spec index 9b9e5015dbc47202d0892e2425624f84dc011911..4dd37cf981435541262c89bdb9d2f4588412c0d7 100644 --- a/crash.spec +++ b/crash.spec @@ -1,45 +1,48 @@ # # crash core analysis suite # -%define anolis_release .0.1 Summary: Kernel analysis utility for live systems, netdump, diskdump, kdump, LKCD or mcore dumpfiles +%define anolis_release .0.2 Name: crash -Version: 7.3.1 -Release: 6%{anolis_release}%{?dist} +Version: 8.0.1 +Release: 2%{anolis_release}%{?dist} License: GPLv3 -Group: Development/Debuggers Source0: https://github.com/crash-utility/crash/archive/crash-%{version}.tar.gz -%ifarch loongarch64 -Source1: gdb-8.1.tar.gz -%else -Source1: http://ftp.gnu.org/gnu/gdb/gdb-7.6.tar.gz -%endif +Source1: http://ftp.gnu.org/gnu/gdb/gdb-10.2.tar.gz URL: https://crash-utility.github.io ExclusiveOS: Linux ExclusiveArch: %{ix86} ia64 x86_64 ppc ppc64 s390 s390x %{arm} aarch64 ppc64le loongarch64 -Buildroot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot-%(%{__id_u} -n) -BuildRequires: ncurses-devel zlib-devel lzo-devel bison snappy-devel libzstd-devel texinfo flex -Requires: binutils +BuildRequires: ncurses-devel zlib-devel lzo-devel snappy-devel bison texinfo libzstd-devel +BuildRequires: gcc gcc-c++ +BuildRequires: make Requires: glibc -Provides: bundled(gdb) = 7.6 +Requires: binutils +Provides: bundled(libiberty) +Provides: bundled(gdb) = 10.2 Provides: /usr/bin/crash Patch0: lzo_snappy_zstd.patch -Patch1: rhel8_build.patch -Patch2: rhel8_freepointer.patch -Patch3: 0001-arm64-Support-overflow-stack-panic.patch -Patch4: 0002-defs.h-fix-breakage-of-compatibility-of-struct-symbo.patch -Patch5: 0001-Fix-pvops-Xen-detection-for-arm-machine.patch -Patch6: 0002-Handle-blk_mq_ctx-member-changes-for-kernels-5.16-rc.patch -Patch7: 0003-Fix-for-timer-r-option-to-display-all-the-per-CPU-cl.patch -Patch8: 0004-Fix-for-bt-v-option-to-display-the-stack-end-address.patch -Patch9: 0005-Fix-for-HZ-calculation-on-Linux-5.14-and-later.patch -Patch10: 0006-memory-Handle-struct-slab-changes-on-Linux-5.17-rc1-.patch -Patch11: 0007-Move-the-initialization-of-boot_date-to-task_init.patch -Patch12: 0008-Remove-ptype-command-from-ps-t-option-to-reduce-memo.patch -Patch13: 0009-Improve-the-ps-performance-for-vmcores-with-large-nu.patch -Patch14: 0010-arm64-Fix-segfault-by-bt-command-with-offline-cpus.patch -Patch15: 0011-Fix-for-kmem-s-S-and-bt-F-F-on-Linux-5.17-rc1.patch -Patch16: 0001-crash-Add-LoongArch-support.patch +Patch1: crash-8.0.1_build.patch +Patch2: 0001-ppc64-update-the-NR_CPUS-to-8192.patch +Patch3: 0001-sbitmapq-remove-struct-and-member-validation-in-sbit.patch +Patch4: 0002-sbitmapq-fix-invalid-offset-for-sbitmap_queue_alloc_.patch +Patch5: 0003-sbitmapq-fix-invalid-offset-for-sbitmap_queue_round_.patch +Patch6: 0004-sbitmapq-fix-invalid-offset-for-sbitmap_word_depth-o.patch +Patch7: 0005-Makefile-add-missing-crash_target.o-to-be-cleaned.patch +Patch8: 0006-bt-x86_64-filter-out-idle-task-stack.patch +Patch9: 0007-bt-arm64-add-support-for-bt-n-idle.patch +Patch10: 0008-gdb-print-details-of-unnamed-struct-and-union.patch +Patch11: 0009-Enhance-dev-d-D-options-to-support-blk-mq-sbitmap.patch +Patch12: 0010-Fix-for-dev-d-D-options-to-support-blk-mq-change-on-.patch +Patch13: 0011-Doc-update-man-page-for-the-bpf-and-sbitmapq-command.patch +Patch14: 0012-sbitmapq-Fix-for-sbitmap_queue-without-ws_active-mem.patch +Patch15: 0013-sbitmapq-Fix-for-sbitmap_word-without-cleared-member.patch +Patch16: 0014-sbitmapq-Fix-for-sbitmap_queue-without-min_shallow_d.patch +Patch17: 0015-Make-dev-d-D-options-parse-sbitmap-on-Linux-4.18-and.patch + +Patch1000: 0001-crash-add-loongarch-support.patch +Patch1001: 0001-LoongArch64-Add-kaslr-command-line-option-support.patch +Patch1002: 0003-LoongArch64-Do-not-verify-temporarily-generated-relo.patch +Patch1003: 0001-LoongArch64-Do-not-verify-temporary-symbols-generate.patch %description The core analysis suite is a self-contained tool that can be used to @@ -48,9 +51,8 @@ netdump, diskdump and kdump packages from Red Hat Linux, the mcore kernel patch offered by Mission Critical Linux, or the LKCD kernel patch. %package devel -Requires: %{name} = %{version}, zlib-devel lzo-devel snappy-devel +Requires: %{name} = %{version}, zlib-devel Summary: kernel crash analysis utility for live systems, netdump, diskdump, kdump, LKCD or mcore dumpfiles -Group: Development/Debuggers %description devel The core analysis suite is a self-contained tool that can be used to @@ -61,7 +63,7 @@ offered by Mission Critical Linux, or the LKCD kernel patch. %package doc Summary: Documents for %{name} BuildArch: noarch -Requires: %{name} = %{version}-%{release} +Requires: %{name} = %{?epoch:%{epoch}:}%{version}-%{release} %description doc Doc pages for %{name}. @@ -69,8 +71,8 @@ Doc pages for %{name}. %prep %setup -n %{name}-%{version} -q %patch0 -p1 -b lzo_snappy_zstd.patch -%patch1 -p1 -b rhel8_build.patch -%patch2 -p1 -b rhel8_freepointer.patch +%patch1 -p1 -b crash-8.0.1_build.patch +%patch2 -p1 %patch3 -p1 %patch4 -p1 %patch5 -p1 @@ -84,409 +86,273 @@ Doc pages for %{name}. %patch13 -p1 %patch14 -p1 %patch15 -p1 -%ifarch loongarch64 %patch16 -p1 -%endif +%patch17 -p1 + +%patch1000 -p1 +%patch1001 -p1 +%patch1002 -p1 +%patch1003 -p1 %build + cp %{SOURCE1} . -#make RPMPKG="%{version}-%{release}" CFLAGS="%{optflags}" -make RPMPKG="%{version}-%{release}" CFLAGS="%{optflags}" LDFLAGS="%{build_ldflags}" +make -j`nproc` RPMPKG="%{version}-%{release}" CFLAGS="%{optflags}" CXXFLAGS="%{optflags}" LDFLAGS="%{build_ldflags}" %install rm -rf %{buildroot} mkdir -p %{buildroot}%{_bindir} -make DESTDIR=%{buildroot} install +%make_install mkdir -p %{buildroot}%{_mandir}/man8 cp -p crash.8 %{buildroot}%{_mandir}/man8/crash.8 mkdir -p %{buildroot}%{_includedir}/crash chmod 0644 defs.h cp -p defs.h %{buildroot}%{_includedir}/crash -%clean -rm -rf %{buildroot} - %files -%defattr(-,root,root,-) %{_bindir}/crash %{_mandir}/man8/crash.8* %files devel -%defattr(-,root,root,-) %{_includedir}/* %files doc %doc README COPYING3 %changelog -* Fri Sep 23 2022 Weisson - 7.3.1-6.0.1 +* Wed Jan 4 2023 Liwei Ge - 8.0.1-2.0.2 +- Add LoongArch support (Youling Tang) + +* Thu Dec 08 2022 Weisson - 8.0.1-2.0.1 - Add doc sub package -* Tue Jul 12 2022 Youling Tang - 7.3.1-6 -- Add LoongArch support +* Fri Jun 10 2022 Lianbo Jiang - 8.0.1-2 +- Fix for the "struct -o" command issue +- Enhance the "dev -d" and "bt" commands -* Tue Feb 08 2022 Lianbo Jiang - 7.3.1-5 -- Rebuild for osci badfuncs issue +* Sat May 14 2022 Lianbo Jiang - 8.0.1-1 +- Rebase to upstream crash 8.0.1 -* Mon Feb 07 2022 Lianbo Jiang - 7.3.1-4 +* Mon Feb 07 2022 Lianbo Jiang - 8.0.0-5 - Fix segfault on aarch64 for "bt -a|-c" command +- Fix segfault for the "l" command of gdb - Fix HZ calculation on Linux 5.14 and later -- Fix for "timer -r" option to display all the per-CPU clocks +- Fix for other issues + +* Wed Dec 29 2021 Lianbo Jiang - 8.0.0-4 +- Handle blk_mq_ctx member changes for kernels 5.16-rc1 and later -* Mon Dec 13 2021 Lianbo Jiang - 7.3.1-3 +* Mon Dec 13 2021 Lianbo Jiang - 8.0.0-3 - Fix segmentation fault caused by crash extension modules - Support the overflow stack exception handling on aarch64 -* Tue Dec 07 2021 Lianbo Jiang - 7.3.1-2 +* Mon Dec 06 2021 Lianbo Jiang - 8.0.0-2 - Enable ZSTD feature support -* Fri Nov 26 2021 Lianbo Jiang - 7.3.1-1 -- Rebase to the latest crash-7.3.1 +* Thu Nov 25 2021 Lianbo Jiang - 8.0.0-1 +- Rebase to upstream 8.0.0 -* Thu Nov 18 2021 Lianbo Jiang - 7.3.0-3 -- Fix for "sched: Change task_struct::state" -- Fix for "sched: move CPU field back into thread_info if THREAD_INFO_IN_TASK=y" -- Fix live debugging with lockdown=integrity -- Fix 'waitq' command for Linux 4.13 and later kernels -- Fix for "kmem -s|-S" option on Linux 5.7 and later kernels +* Mon Aug 09 2021 Mohan Boddu - 7.3.0-6 +- Rebuilt for IMA sigs, glibc 2.34, aarch64 flags + Related: rhbz#1991688 + +* Thu Jul 22 2021 Lianbo Jiang - 7.3.0-5 +- Fix for handling task_struct state member changes(kernels >= 5.14-rc1) + +* Wed Jul 07 2021 Lianbo Jiang - 7.3.0-4 +- Fix memory layout for aarch64 -* Fri May 14 2021 Lianbo Jiang - 7.3.0-2 -- Update the sha512 hash in the sources file to solve the - compilation issues +* Mon Jul 05 2021 Lianbo Jiang - 7.3.0-3 +- Fix "kmem -n|-p" options display wrong values. -* Thu May 13 2021 Lianbo Jiang - 7.3.0-1 +* Fri Jun 11 2021 Lianbo Jiang - 7.3.0-2 +- Fix for "kmem -s|-S" option on Linux 5.7 and later kernels + +* Mon May 10 2021 Lianbo Jiang - 7.3.0-1 - Rebase to upstream 7.3.0 -* Tue Dec 1 2020 Bhupesh Sharma - 7.2.9-2 -- Fix the sources file to add gdb-7.6 tarball - [The line was somehow removed when using rhpkg new-sources to - update the crash tarball location] - Resolves: rhbz#1881854 - -* Tue Dec 1 2020 Bhupesh Sharma - 7.2.9-1 -- Rebase to upstream crash version 7.2.9 -- Also minimize the rhel-only patches to the bare minimum. - Resolves: rhbz#1881854 - -* Thu Nov 5 2020 Bhupesh Sharma - 7.2.8-8 -- crash/arm64: Fix arm64 read error with 'idmap_ptrs_per_pgd' symbol with debug kernel - Resolves: rhbz#1876039 - -* Mon Aug 17 2020 Bhupesh Sharma - 7.2.8-7 -- crash/sadump, kaslr: fix failure of calculating kaslr_offset due to an sadump format restriction - Resolves: rhbz#1855527 - -* Fri Aug 7 2020 Bhupesh Sharma - 7.2.8-6 -- aarch64: Revert to reading CONFIG_ARM64_USER_VA_BITS_52 and CONFIG_ARM64_PA_BITS=52 for 52-bit VA/PA space. - Resolves: rhbz#1861086 - -* Mon Jul 27 2020 Bhupesh Sharma - 7.2.8-5 -- aarch64: Support reading extended 52-bit address space via crash-utility - Resolves: rhbz#1861086 - -* Fri Jul 10 2020 Bhupesh Sharma - 7.2.8-4 -- Replace people.redhat.com references with github equivalents. - Resolves: rhbz#1851745 - -* Mon Jun 22 2020 Bhupesh Sharma - 7.2.8-3 -- Fix for reading compressed kdump dumpfiles from systems with physical memory - Resolves: rhbz#1819606 - -* Mon Jun 8 2020 Bhupesh Sharma - 7.2.8-2 -- Remove wget from BuildRequires section - Resolves: rhbz#1838322 - -* Fri Jun 5 2020 Bhupesh Sharma - 7.2.8-1 -- Rebase to latest upstream release 7.2.8 - Resolves: rhbz#1838322 - -* Mon Feb 3 2020 Dave Anderson - 7.2.7-3 -- Rebase to github commit 6c1c8ac6 - Resolves: rhbz#1738619 -- Fix "log -a" option - Resolves: rhbz#1785537 -- Fix for ELF kdump vmcores form s390x KASLR kernels - Resolves: rhbz#1786996 - -* Mon Nov 11 2019 Dave Anderson - 7.2.7-2 -- Rebase to latest upstream sources - Resolves: rhbz#1738619 -- Support for KASLR on s390x - Resolves: rhbz# 1753172 - -* Mon Jun 10 2019 Dave Anderson - 7.2.6-2 -- Fix "p" command regression - Resolves: rhbz#1718417 -- Fix arm64 debug kernel read error message during initialization - Resolves: rhbz#1718736 +* Thu Apr 15 2021 Mohan Boddu - 7.2.9-7 +- Rebuilt for RHEL 9 BETA on Apr 15th 2021. Related: rhbz#1947937 + +* Tue Apr 13 2021 Lianbo Jiang - 7.2.9-6 +- Update to the latest upstream: commit <8dfc228b29ae> + +* Mon Mar 08 2021 Lianbo Jiang - 7.2.9-5 +- Fix Segmentation fault +- Update to the latest upstream: commit <9c0c6c1b3750> + +* Fri Feb 05 2021 Lianbo Jiang - 7.2.9-4 +- Update to the latest upstream: commit + +* Tue Jan 26 2021 Fedora Release Engineering - 7.2.9-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_34_Mass_Rebuild + +* Fri Dec 11 2020 Lianbo Jiang - 7.2.9-2 +- Add support for lockless ringbuffer + +* Wed Nov 25 2020 Lianbo Jiang - 7.2.9-1 +- Update to latest upstream release + +* Mon Jul 27 2020 Fedora Release Engineering - 7.2.8-5 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild + +* Mon Jul 13 2020 Tom Stellard - 7.2.8-4 +- Use make macros +- https://fedoraproject.org/wiki/Changes/UseMakeBuildInstallMacro + +* Tue Jun 30 2020 Jeff Law - 7.2.8-3 +- Disable LTO + +* Fri Jan 31 2020 Dave Anderson - 7.2.8-2 +- Update to latest upstream release +- Fix aarch64 build for gcc-10 -fno-common + +* Tue Jan 28 2020 Fedora Release Engineering - 7.2.7-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild + +* Mon Sep 23 2019 Dave Anderson - 7.2.7-1 +- Update to latest upstream release + +* Wed Jul 24 2019 Fedora Release Engineering - 7.2.6-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_31_Mass_Rebuild * Mon May 6 2019 Dave Anderson - 7.2.6-1 -- Rebase to latest upstream sources - Resolves: rhbz#1686560 -- Utilize the VMCOREINFO PT_NOTE in /proc/kcore header - Resolves: rhbz#1627528 -- Support extraction of CONFIG_PROC_VMCORE_DEVICE_DUMP data from dumpfile header - Resolves: rhbz#1702535 - -* Thu Feb 14 2019 Dave Anderson - 7.2.3-18 -- Fix "files -c" and "files -p" options - Resolves: rhbz#1673285 - -* Mon Feb 11 2019 Dave Anderson - 7.2.3-17 -- Support for CONFIG_ARM64_USER_VA_BITS_52 and CONFIG_ARM64_PA_BITS=52 - Resolves: rhbz#1670099 - -* Tue Jan 8 2019 Dave Anderson - 7.2.3-16 -- Resurrect "dev -p" option. -- Fix "dev -[dD]" options to account for request_queue.in_flight[] removal. - Resolves: rhbz#1662039 -- Command line input fixes - Resolves: rhbz#1664061 - -* Thu Dec 13 2018 Dave Anderson - 7.2.3-15 -- Increase ppc64 MAX_PHYSMEM_BITS to match 4.18.0-35.el8 kernel backport - Resolves: rhbz#1658628 - -* Thu Nov 29 2018 Dave Anderson - 7.2.3-14 -- Fix for ARM64 "ps -s" memory allocation failure - Resolves: rhbz#1654582 - -* Thu Oct 25 2018 Dave Anderson - 7.2.3-13 -- Change "bt" warnings when exception RIP is legitimate mapped address - Resolves: rhbz#1642221 - -* Mon Oct 15 2018 Dave Anderson - 7.2.3-12 -- Address covscan issues - Resolves: rhbz#1602466 -- Fix for x86_64 5-level pagetable vmalloc range expansion - Resolves: rhbz#1637125 - -* Wed Oct 4 2018 Dave Anderson - 7.2.3-11 -- Fix ppc64 backtrace issues - Resolves: rhbz#1633525 - -* Wed Sep 19 2018 Dave Anderson - 7.2.3-10 -- Address annocheck build issues - Resolves: rhbz#1624101 - -* Thu Aug 9 2018 Dave Anderson - 7.2.3-9 -- Fix for live system (/proc/kcore) access when KALSR is in effect - Resolves: rhbz#1611916 - -* Mon Jul 16 2018 Dave Anderson - 7.2.3-8 -- Rebase to github commits 9b494b70_to_eb823b79 - Resolves: rhbz#1563495 - -* Fri Jun 22 2018 Dave Anderson - 7.2.3-7 -- Rebase to github commits 28fa7bd0 to 02efd083 - Resolves: rhbz#1590751 - Resolves: rhbz#1592746 - -* Tue Jun 12 2018 Dave Anderson - 7.2.3-6 -- github commit 1926150e: fix ppc64/ppc6le stacksize calculation - -* Fri Jun 8 2018 Dave Anderson - 7.2.3-5 -- Remove /dev/mem readmem error message and /proc/kcore switch messages - Resolves: rhbz#1585944 - -* Fri Jun 1 2018 Dave Anderson - 7.2.3-4 -- Rebase to latest upstream sources - -* Tue Nov 21 2017 Dave Anderson - 7.2.0-2 -- Rebase to github commits da9bd35a to e2efacdd - Resolves: rhbz#1497316 - -* Wed Nov 1 2017 Dave Anderson - 7.2.0-1 -- Rebase to upstream version 7.2.0 -- Rebase to github commits da9bd35a_to_e2efacdd.patch - Resolves: rhbz#1497316 -- ppc64le: fix for "WARNING: cannot access vmalloc'd module memory" - Resolves: rhbz#1485391 -- Support for analyzing an SADUMP crash dump if KASLR is enabled - Resolves: rhbz#1504467 - -* Wed May 3 2017 Dave Anderson - 7.1.9-2 -- Rebase to github commits 87179026 to ad3b8476 - Resolves: rhbz#1393534 -- Prohibit native gdb disassemble command when KASLR - Resolves: rhbz#1445649 +- Update to latest upstream release + +* Sun Feb 17 2019 Igor Gnatenko - 7.2.5-3 +- Rebuild for readline 8.0 + +* Thu Jan 31 2019 Fedora Release Engineering - 7.2.5-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_30_Mass_Rebuild + +* Fri Jan 11 2019 Dave Anderson - 7.2.5-1 +- Update to latest upstream release + +* Mon Sep 24 2018 Dave Anderson - 7.2.4-1 +- Update to latest upstream release + +* Thu Jul 12 2018 Fedora Release Engineering - 7.2.3-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild + +* Fri May 18 2018 Dave Anderson - 7.2.3-1 +- Update to latest upstream release + +* Fri Feb 23 2018 Dave Anderson - 7.2.1-2 +- Use RPM build flags for LDFLAGS + +* Fri Feb 16 2018 Dave Anderson - 7.2.1-1 +- Update to latest upstream release + +* Wed Feb 07 2018 Fedora Release Engineering - 7.2.0-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild + +* Mon Oct 2 2017 Dave Anderson - 7.2.0-1 +- Update to latest upstream release + +* Wed Aug 02 2017 Fedora Release Engineering - 7.1.9-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Binutils_Mass_Rebuild + +* Wed Jul 26 2017 Fedora Release Engineering - 7.1.9-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild * Mon Apr 24 2017 Dave Anderson - 7.1.9-1 -- Rebase to upstream version 7.1.9 - Resolves: rhbz#1393534 -- Fix gdb "set scope" option for KASLR kernels. - Resolves: rhbz#1440725 -- Fix for the determination of the x86_64 "phys_base" value when it is - not passed in the VMCOREINFO data of ELF vmcores - Resolves: rhbz#1439170 - -* Wed Mar 8 2017 Dave Anderson - 7.1.8-2 -- mod [-sS] command may erroneously reassign module symbol addresses - Resolves: rhbz#1430091 - -* Fri Feb 24 2017 Dave Anderson - 7.1.8-1 -- Rebase to upstream version 7.1.8 - Resolves: rhbz#1393534 -- POWER9 - Power ISA 3.0 related support for crash utility - Resolves: rhbz#1368711 -- crash package update - ppc64/ppc64le - Resolves: rhbz#1384944 -- exception RIP: unknown or invalid address - Resolves: rhbz#1350457 -- Crash does not always parse correctly the modules symbol tables - Resolves: rhbz#1360415 -- ARM64: crash live system from: WARNING: cannot read linux_banner string - Resolves: rhbz#1392007 -- kmem: invalid structure member offset: page_count - Resolves: rhbz#1392011 -- Kernel address space randomization [KASLR] support - Resolves: rhbz#1392658 -- invalid structure size: tnt - Resolves: rhbz#1420653 - -* Wed Sep 14 2016 Dave Anderson - 7.1.5-2 -- Fix for kernel module symbol gathering when the ordering of module - symbol name strings does not match the order of the kernel_symbol - structures. -- Resolves: rhbz#1375130 +- Update to latest upstream release + +* Thu Feb 23 2017 Dave Anderson - 7.1.8-1 +- Update to latest upstream release + +* Fri Feb 10 2017 Fedora Release Engineering - 7.1.7-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild + +* Thu Jan 12 2017 Igor Gnatenko - 7.1.7-2 +- Rebuild for readline 7.x + +* Tue Dec 6 2016 Dave Anderson - 7.1.7-1 +- Update to latest upstream release + +* Fri Oct 14 2016 Dave Anderson - 7.1.6-1 +- Update to latest upstream release +- Fix for RHBZ#1044119 - crash bundles gdb + +* Thu May 5 2016 Dave Anderson - 7.1.5-2 +- BZ #1333295 - FTBFS due compiler warnings in elf64-s390.c * Thu Apr 28 2016 Dave Anderson - 7.1.5-1 -- Rebase to upstream version 7.1.5 - Resolves: rhbz#1292566 -- Decode clflushopt instruction - Resolves: rhbz#1262479 -- Support AArch64 QEMU generated dumps - Resolves: rhbz#1299873 -- crash: zero-size memory allocation (aarch64) - Resolves: rhbz#1312738 - -* Tue Apr 5 2016 Dave Anderson - 7.1.2-4 -- crash: fails to read excluded pages by default on sadump-related format - Resolves: rhbz#1304260 - -* Mon Nov 23 2015 Dave Anderson - 7.1.2-3 -- crash fails to read or wrongly reads some parts of memory in sadump vmcore format - Resolves: rhbz#1282997 - -* Tue Aug 4 2015 Dave Anderson - 7.1.2-2 -- Fix "kmem -s
", "bt -F[F]", and "rd -S[S]" options in kernels - configured with CONFIG_SLUB having multiple-page slabs. - Resolves: rhbz#1244003 -- Fix for SIGSEGV generated by "bt -[f|F]" in ARM64 kernels. - Resolves: rhbz#1248859 - +- Update to latest upstream release + +* Wed Feb 03 2016 Fedora Release Engineering - 7.1.4-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_24_Mass_Rebuild + +* Thu Dec 17 2015 Dave Anderson - 7.1.4-1 +- Update to latest upstream release + +* Thu Sep 3 2015 Dave Anderson - 7.1.3-1 +- Update to latest upstream release + * Mon Jul 13 2015 Dave Anderson - 7.1.2-1 -- Rebase to upstream version 7.1.2 - Resolves: rhbz#1207696 -- Fix several ppc64 backtrace issues - Resolves: rhbz#1235447 +- Update to latest upstream release -* Fri Jun 05 2015 Dave Anderson - 7.1.1-2 -- ARM64 backtrace enhancements - Resolves: rhbz#1227508 +* Wed Jun 17 2015 Fedora Release Engineering - 7.1.1-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild * Thu May 28 2015 Dave Anderson - 7.1.1-1 -- Rebase to upstream version 7.1.1 - Resolves: rhbz#1207696 -- Display s390x vector registers from a kernel dump. - Resolves: rhbz#1182161 -- Fix date displayed on initial system banner and by the "sys" command on ARM64. - Resolves: rhbz#1223044 -- Fix ARM64 page size calculation on 4.1 and later kernels. - Resolves: rhbz#1222645 - -* Tue Apr 21 2015 Dave Anderson - 7.0.9-6 -- Calculate ARM64 virtual memory layout based upon struct page size - Resolves: rhbz#1204941 - -* Tue Apr 7 2015 Dave Anderson - 7.0.9-5 -- Support new sadump format that can represent more than 16 TB physical memory space - Resolves: rhbz#1182383 - -* Mon Jan 26 2015 Dave Anderson - 7.0.9-4 - Fix ppc64 "bt" command for active tasks in compressed kdumps. - Resolves: rhbz#1184401 - -* Mon Jan 12 2015 Dave Anderson - 7.0.9-3 - Fix "bt" command mislabeling errors. - Resolves: rhbz#1179476 - -* Mon Dec 08 2014 Dave Anderson - 7.0.9-2 -- Use registers from QEMU-generated ELF and compressed kdump headers - for active task backtraces. -- Resolves: rhbz#1169555 - -* Fri Nov 14 2014 Dave Anderson - 7.0.9-1 -- Rebase to upstream version 7.0.9. -- Resolves: rhbz#1110513 - -* Tue Sep 23 2014 Dave Anderson - 7.0.8-2 -- Fix ps performance patch regression on live systems. -- Resolves: rhbz#1134177 -- Minor build-related fixes for ppc64le. -- Resolves: rhbz#1123991 - -* Fri Sep 12 2014 Dave Anderson - 7.0.8-1 -- Rebase to upstream version 7.0.8. -- Resolves: rhbz#1110513 -- Fix to calculate the physical base address of dumpfiles created - by a "virsh dump" of an OVMF guest. -- Resolves: rhbz#1080698 -- Support for aarch64 architecture. -- Resolves: rhbz#1110551 -- Fix to prevent crash from spinning endlessly on a corrupted/truncated - dumpfile whose bitmap data is not wholly contained within the file. -- Resolves: rhbz#1114088 -- Support for ppc64le architecture. -- Resolves: rhbz#1123991 - -* Tue Jan 28 2014 Daniel Mach - 7.0.2-6 -- Mass rebuild 2014-01-24 - -* Fri Jan 24 2014 Dave Anderson - 7.0.2-5 -- Fix for a missing kernel-mode exception frame dump by the x86_64 - "bt" command if a page fault was generated by a bogus RIP. -- Resolves: rhbz#1057353 -- Fix for the x86_64 "bt" command to prevent an unwarranted message - indicating "WARNING: possibly bogus exception frame" generated - from a blocked kernel thread that was in the process of exec'ing - a user process via the call_usermodehelper() facility. -- Resolves: rhbz#1057357 - -* Fri Jan 10 2014 Dave Anderson - 7.0.2-4 -- Fixes for "kmem -S" command for CONFIG_SLUB. -- Resolves: rhbz#1045591 -- Increase S390X NR_CPUS -- Resolves: rhbz#1051156 - -* Fri Dec 27 2013 Daniel Mach - 7.0.2-3 -- Mass rebuild 2013-12-27 - -* Tue Oct 29 2013 Dave Anderson - 7.0.2-2 -- Compressed kdump 46-bit physical memory support - Resolves: rhbz#1015250 -- Fix incorrect backtrace for dumps taken with "virsh dump --memory-only" - Resolves: rhbz#1020469 -- Fix cpu number display on systems with more than 254 cpus - Resolves: rhbz#1020536 +- Update to latest upstream release -* Wed Sep 04 2013 Dave Anderson - 7.0.2-1 +* Mon Mar 2 2015 Dave Anderson - 7.1.0-3 +- Support increment of Linux version from 3 to 4 + +* Sat Feb 21 2015 Till Maas - 7.1.0-2 +- Rebuilt for Fedora 23 Change + https://fedoraproject.org/wiki/Changes/Harden_all_packages_with_position-independent_code + +* Tue Feb 10 2015 Dave Anderson - 7.1.0-1 +- Update to latest upstream release + +* Fri Nov 15 2014 Dave Anderson - 7.0.9-1 - Update to latest upstream release -- Fix for ppc64 embedded gdb NULL pointer translation sigsegv -- Fix for bt -F failure -* Fri Jul 26 2013 Dave Anderson - 7.0.1-4 -- Add lzo-devel and snappy-devel to crash-devel Requires line +* Mon Sep 15 2014 Dave Anderson - 7.0.8-1 +- Update to latest upstream release +- Add ppc64le as supported architecture for crash package (BZ #1136050) + +* Sat Aug 16 2014 Fedora Release Engineering - 7.0.7-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_22_Mass_Rebuild + +* Wed Jul 02 2014 Dave Anderson - 7.0.7-2 +- Fix FTBS for aarch64 (BZ #1114588) + +* Wed Jun 11 2014 Dave Anderson - 7.0.7-1 +- Update to latest upstream release +- Fix Fedora_21_Mass_Rebuild FTBFS (BZ #1106090) -* Tue Jul 23 2013 Dave Anderson - 7.0.1-3 -- Build with snappy compression support +* Sat Jun 07 2014 Fedora Release Engineering - 7.0.5-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild + +* Fri Feb 28 2014 Dave Anderson - 7.0.5-1 +- Update to latest upstream release +- Use system readline library +- Fix "crash --log vmcore" command for 3.11 and later kernels. + +* Tue Dec 17 2013 Toshio Kuratomi - 7.0.4-2 +- crash bundles gdb which bundles libiberty. Add virtual Provides for + libiberty tracking. Open a bug for unbundling gdb RHBZ#1044119 + +* Mon Dec 16 2013 Dave Anderson - 7.0.4-1 +- Update to latest upstream release + +* Tue Oct 29 2013 Dave Anderson - 7.0.3-1 +- Update to latest upstream release + +* Wed Sep 04 2013 Dave Anderson - 7.0.2-1 +- Update to latest upstream release +- Build with lzo and snappy compression capability -* Tue Jul 9 2013 Dave Anderson - 7.0.1-2 -- Fix for ppc64 Linux 3.10 vmalloc/user-space virtual address translation +* Sat Aug 03 2013 Fedora Release Engineering - 7.0.1-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_20_Mass_Rebuild -* Tue Jun 18 2013 Dave Anderson - 7.0.1-1 +* Mon Jun 17 2013 Dave Anderson - 7.0.1-1 - Update to latest upstream release -- Build with LZO support +- Add aarch64 as an exclusive arch * Tue Apr 9 2013 Dave Anderson - 6.1.6-1 - Update to latest upstream release diff --git a/download b/download deleted file mode 100644 index f9c32aab4c3972a672d34f2a18e79b91a510301c..0000000000000000000000000000000000000000 --- a/download +++ /dev/null @@ -1,3 +0,0 @@ -d197445f6d2b6bbe411a8e5dccee7191 crash-7.3.1.tar.gz -a9836707337e5f7bf76a009a8904f470 gdb-7.6.tar.gz -cc588720438e6e6bf7df192428ad844e gdb-8.1.tar.gz diff --git a/gdb-10.2.tar.gz b/gdb-10.2.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..dfe4b7d83e0f7f0894de0e961490ff600d84e2b5 Binary files /dev/null and b/gdb-10.2.tar.gz differ diff --git a/lzo_snappy_zstd.patch b/lzo_snappy_zstd.patch index 4813ed032737a4e07ad15be0b91e6bef6cbc9f69..52e96e30ee0a1d5ac4956d89f606529a23a47963 100644 --- a/lzo_snappy_zstd.patch +++ b/lzo_snappy_zstd.patch @@ -1,16 +1,16 @@ ---- crash-7.3.1/Makefile.orig -+++ crash-7.3.1/Makefile -@@ -230,7 +230,7 @@ all: make_configure +--- crash-8.0.1/Makefile.orig ++++ crash-8.0.1/Makefile +@@ -256,7 +256,7 @@ all: make_configure gdb_merge: force @if [ ! -f ${GDB}/README ]; then \ - make --no-print-directory gdb_unzip; fi + $(MAKE) gdb_unzip; fi - @echo "${LDFLAGS} -lz -ldl -rdynamic" > ${GDB}/gdb/mergelibs + @echo "${LDFLAGS} -lz -llzo2 -lsnappy -lzstd -ldl -rdynamic" > ${GDB}/gdb/mergelibs @echo "../../${PROGRAM} ../../${PROGRAM}lib.a" > ${GDB}/gdb/mergeobj @rm -f ${PROGRAM} @if [ ! -f ${GDB}/config.status ]; then \ ---- crash-7.3.1/diskdump.c.orig -+++ crash-7.3.1/diskdump.c +--- crash-8.0.1/diskdump.c.orig ++++ crash-8.0.1/diskdump.c @@ -23,6 +23,9 @@ * GNU General Public License for more details. */ diff --git a/rhel8_freepointer.patch b/rhel8_freepointer.patch deleted file mode 100644 index e7aded5112747df8c026403ac0f35f4e0bc51928..0000000000000000000000000000000000000000 --- a/rhel8_freepointer.patch +++ /dev/null @@ -1,29 +0,0 @@ -From e09e3c038c853f9a332cf05a17e5fdee1c7837e0 Mon Sep 17 00:00:00 2001 -From: Lianbo Jiang -Date: Thu, 18 Nov 2021 09:55:45 +0800 -Subject: [PATCH] fix freepointer issue - -Signed-off-by: Lianbo Jiang ---- - memory.c | 5 ++--- - 1 file changed, 2 insertions(+), 3 deletions(-) - -diff --git a/memory.c b/memory.c -index a3cf8a86728d..81db9c7bee9f 100644 ---- a/memory.c -+++ b/memory.c -@@ -19340,9 +19340,8 @@ freelist_ptr(struct meminfo *si, ulong ptr, ulong ptr_addr) - if (VALID_MEMBER(kmem_cache_random)) { - /* CONFIG_SLAB_FREELIST_HARDENED */ - -- if (THIS_KERNEL_VERSION >= LINUX(5,7,0)) -- ptr_addr = (sizeof(long) == 8) ? bswap_64(ptr_addr) -- : bswap_32(ptr_addr); -+ ptr_addr = (sizeof(long) == 8) ? bswap_64(ptr_addr) -+ : bswap_32(ptr_addr); - return (ptr ^ si->random ^ ptr_addr); - } else - return ptr; --- -2.30.2 -