[Crash-utility] [Patch V2 2/2] sparc64 changes
Dave Kleikamp
dave.kleikamp at oracle.com
Mon Mar 28 20:34:57 UTC 2016
On 03/25/2016 02:19 PM, Sam Ravnborg wrote:
> Hi Dave.
>
> A few commnets from reading the patch, as I have no knowledge of the code it patches.
> And comments are biaes towards kernel ways of doing this.
Thanks for the review. I'll clean this up and resubmit.
>
> Sam
>
> On Wed, Mar 23, 2016 at 05:41:08PM -0500, Dave Kleikamp wrote:
>> Based on original work by Karl Volz <karl.volz at oracle.com>
>
> Should this patch follow the kernel standards, then
> the description should be far more elaborated.
> And I dunno if a s-o-b is appropriate too.
Fair enough. I could add a bigger description. I saw no other s-o-b
lines in the crash changesets, but I could put one in and let the
maintainer do what he wants with it.
>
>> @@ -104,6 +104,7 @@ void add_extra_lib(char *);
>> #undef X86_64
>> #undef ARM
>> #undef ARM64
>> +#undef SPARC64
>>
>> #define UNKNOWN 0
>> #define X86 1
>> @@ -117,6 +118,7 @@ void add_extra_lib(char *);
>> #define ARM 9
>> #define ARM64 10
>> #define MIPS 11
>> +#define SPARC64 12
>>
>> #define TARGET_X86 "TARGET=X86"
>> #define TARGET_ALPHA "TARGET=ALPHA"
>> @@ -129,6 +131,7 @@ void add_extra_lib(char *);
>> #define TARGET_ARM "TARGET=ARM"
>> #define TARGET_ARM64 "TARGET=ARM64"
>> #define TARGET_MIPS "TARGET=MIPS"
>> +#define TARGET_SPARC64 "TARGET=SPARC64"
>>
>> #define TARGET_CFLAGS_X86 "TARGET_CFLAGS=-D_FILE_OFFSET_BITS=64"
>> #define TARGET_CFLAGS_ALPHA "TARGET_CFLAGS="
>> @@ -149,6 +152,7 @@ void add_extra_lib(char *);
>> #define TARGET_CFLAGS_MIPS "TARGET_CFLAGS=-D_FILE_OFFSET_BITS=64"
>> #define TARGET_CFLAGS_MIPS_ON_X86 "TARGET_CFLAGS=-D_FILE_OFFSET_BITS=64"
>> #define TARGET_CFLAGS_MIPS_ON_X86_64 "TARGET_CFLAGS=-m32 -D_FILE_OFFSET_BITS=64"
>> +#define TARGET_CFLAGS_SPARC64 "TARGET_CFLAGS=-mcpu=v9 -fPIC -fno-builtin"
> Are you missing -m64 here? At least we use -m64 when building the kernel.
Now that I think about it. I probably have too much here. The installed
compiler should have the proper defaults for building user-space. I'm
sure this dates back to developing on an early toolchain.
>> #define GDB_TARGET_DEFAULT "GDB_CONF_FLAGS="
>> #define GDB_TARGET_ARM_ON_X86 "GDB_CONF_FLAGS=--target=arm-elf-linux"
>> @@ -378,6 +382,9 @@ get_current_configuration(struct supported_gdb_version *sp)
>> #ifdef __mips__
>> target_data.target = MIPS;
>> #endif
>> +#if defined(__sparc__) && defined(__arch64__)
>> + target_data.target = SPARC64;
>> +#endif
>
> In another place in the patch following is used to detect sparc64:
>> +#ifdef __sparc_v9__
>> +#define SPARC64
>> +#endif
>
> Looks strange that two different approaches are used.
Agreed. I think I'll use __sparc_v9__ in both places.
>> +#ifdef NEED_ALIGNED_MEM_ACCESS
>> +
>> +#define DEF_LOADER(TYPE) \
>> +static inline TYPE \
>> +load_##TYPE (char *addr) \
>> +{ \
>> + TYPE ret; \
>> + size_t i = sizeof(TYPE); \
>> + while (i--) \
>> + ((char *)&ret)[i] = addr[i]; \
>> + return ret; \
>> +}
>> +
>> +DEF_LOADER(int);
>> +DEF_LOADER(uint);
>> +DEF_LOADER(long);
>> +DEF_LOADER(ulong);
>> +DEF_LOADER(ulonglong);
>> +DEF_LOADER(ushort);
>> +DEF_LOADER(short);
>> +typedef void *pointer_t;
>> +DEF_LOADER(pointer_t);
>> +
>> +#define LOADER(TYPE) load_##TYPE
>> +
>> +#define INT(ADDR) LOADER(int) ((char *)(ADDR))
>> +#define UINT(ADDR) LOADER(uint) ((char *)(ADDR))
>> +#define LONG(ADDR) LOADER(long) ((char *)(ADDR))
>> +#define ULONG(ADDR) LOADER(ulong) ((char *)(ADDR))
>> +#define ULONGLONG(ADDR) LOADER(ulonglong) ((char *)(ADDR))
>> +#define ULONG_PTR(ADDR) ((ulong *) (LOADER(pointer_t) ((char *)(ADDR))))
>> +#define USHORT(ADDR) LOADER(ushort) ((char *)(ADDR))
>> +#define SHORT(ADDR) LOADER(short) ((char *)(ADDR))
>> +#define UCHAR(ADDR) *((unsigned char *)((char *)(ADDR)))
>> +#define VOID_PTR(ADDR) ((void *) (LOADER(pointer_t) ((char *)(ADDR))))
>> +
>> +#else
>> +
>> #define INT(ADDR) *((int *)((char *)(ADDR)))
>> #define UINT(ADDR) *((uint *)((char *)(ADDR)))
>> #define LONG(ADDR) *((long *)((char *)(ADDR)))
>> @@ -2195,6 +2246,8 @@ struct builtin_debug_table {
>> #define UCHAR(ADDR) *((unsigned char *)((char *)(ADDR)))
>> #define VOID_PTR(ADDR) *((void **)((char *)(ADDR)))
>>
>> +#endif /* NEED_ALIGNED_MEM_ACCESS */
>> +
>
> The NEED_ALIGNED_MEM_ACCESS is generic - and could have been
> handled in a dedicated patch.
Makes sense.
>>
>> +#ifdef SPARC64
>> +#define _64BIT_
>> +#define MACHINE_TYPE "SPARC64"
>> +
>> +#define PTOV(X) \
>> + ((unsigned long)(X)-(machdep->machspec->phys_offset)+(machdep->kvbase))
>> +#define VTOP(X) \
>> + ((unsigned long)(X)-(machdep->kvbase)+(machdep->machspec->phys_offset))
> Some spaces would make wonders for readability.
agreed.
>
>> +extern int sparc64_IS_VMALLOC_ADDR(ulong vaddr);
>> +#define IS_VMALLOC_ADDR(X) sparc64_IS_VMALLOC_ADDR((ulong)(X))
>> +#define PAGE_SHIFT (13)
>> +#define PAGE_SIZE (1UL << PAGE_SHIFT)
>> +#define PAGE_MASK (~(PAGE_SIZE-1))
>> +#define PAGEBASE(X) (((ulong)(X)) & (ulong)machdep->pagemask)
>> +#define THREAD_SIZE (2*PAGE_SIZE)
> Spaces missing again.
okay
>> +/* S3 Core
>> + * Core 48-bit physical address supported.
>> + * Bit 47 distinguishes memory or I/O. When set to "1" it is I/O.
>> + */
>> +#define PHYS_MASK_SHIFT (47)
>> +#define PHYS_MASK (((1UL) << PHYS_MASK_SHIFT) - 1)
>> +
>> +typedef signed int s32;
>> +
>> +/*
>> + * This next two defines are convenience defines for normal page table.
>> + */
>> +#define PTES_PER_PAGE (1UL << (PAGE_SHIFT - 3))
>> +#define PTES_PER_PAGE_MASK (PTES_PER_PAGE - 1)
>> +
>> +/* 4-levels / 8K pages */
>> +#define PG_LVL4_PDIRS_BITS (53)
>> +#define PG_LVL4_PGDIR_SHIFT (43)
>> +#define PG_LVL4_PTRS_PER_PGD (1024)
>> +#define PG_LVL4_PUD_SHIFT (33)
>> +#define PG_LVL4_PTRS_PER_PUD (1024)
>> +#define PG_LVL4_PMD_SHIFT (23)
>> +#define PG_LVL4_PTRS_PER_PMD (1024)
>> +#define PG_LVL4_PTRS_PER_PTE (1UL << (PAGE_SHIFT-3))
>
> If these definitions was a copy of the kernel definitions,
> then it would be much easier to follow and check.
> From the kernel:
> /* PMD_SHIFT determines the size of the area a second-level page
> * table can map
> */
> #define PMD_SHIFT (PAGE_SHIFT + (PAGE_SHIFT-3))
> #define PMD_SIZE (_AC(1,UL) << PMD_SHIFT)
> #define PMD_MASK (~(PMD_SIZE-1))
> #define PMD_BITS (PAGE_SHIFT - 3)
>
> /* PUD_SHIFT determines the size of the area a third-level page
> * table can map
> */
> #define PUD_SHIFT (PMD_SHIFT + PMD_BITS)
> #define PUD_SIZE (_AC(1,UL) << PUD_SHIFT)
> #define PUD_MASK (~(PUD_SIZE-1))
> #define PUD_BITS (PAGE_SHIFT - 3)
>
> /* PGDIR_SHIFT determines what a fourth-level page table entry can map */
> #define PGDIR_SHIFT (PUD_SHIFT + PUD_BITS)
> #define PGDIR_SIZE (_AC(1,UL) << PGDIR_SHIFT)
> #define PGDIR_MASK (~(PGDIR_SIZE-1))
> #define PGDIR_BITS (PAGE_SHIFT - 3)
I'll redo those.
>> +/* Down one huge page */
>> +#define PG_LVL4_SPARC64_USERSPACE_TOP (-(1UL << 23UL))
> If 23 is PG_LVL4_PMD_SHIFT - then use this constant.
yep
>
>> +#define PAGE_PMD_HUGE (0x0100000000000000UL)
>> +#define HPAGE_SHIFT (23)
>
>> +
>> +/* These are for SUN4V. */
>> +#define _PAGE_VALID (0x8000000000000000UL)
>> +#define _PAGE_NFO_4V (0x4000000000000000UL)
>> +#define _PAGE_MODIFIED_4V (0x2000000000000000UL)
>> +#define _PAGE_ACCESSED_4V (0x1000000000000000UL)
>> +#define _PAGE_READ_4V (0x0800000000000000UL)
>> +#define _PAGE_WRITE_4V (0x0400000000000000UL)
>> +#define _PAGE_PADDR_4V (0x00FFFFFFFFFFE000UL)
>> +#define _PAGE_PFN_MASK (_PAGE_PADDR_4V)
>> +#define _PAGE_P_4V (0x0000000000000100UL)
>> +#define _PAGE_EXEC_4V (0x0000000000000080UL)
>> +#define _PAGE_W_4V (0x0000000000000040UL)
>> +#define _PAGE_PRESENT_4V (0x0000000000000010UL)
>> +#define _PAGE_SZALL_4V (0x0000000000000007UL)
>> +/* There are other page sizes. Some supported. */
>> +#define _PAGE_SZ4MB_4V (0x0000000000000003UL)
>> +#define _PAGE_SZ512K_4V (0x0000000000000002UL)
>> +#define _PAGE_SZ64K_4V (0x0000000000000001UL)
>> +#define _PAGE_SZ8K_4V (0x0000000000000000UL)
>> +
>> +#define SPARC64_MODULES_VADDR (0x0000000010000000UL)
>> +#define SPARC64_MODULES_END (0x00000000f0000000UL)
>
>> +#define LOW_OBP_ADDRESS (0x00000000f0000000UL)
>> +#define HI_OBP_ADDRESS (0x0000000100000000UL)
> These two are not used and can be deleted.
> Did not check all of tham but OBP stuff triggered me.
Missed these when cleaning out obsolete code.
>> +#define SPARC64_VMALLOC_START (0x0000000100000000UL)
>> +
>> +#define SPARC64_STACK_SIZE 0x4000
>> +#define PTRS_PER_PGD (1024)
>> +
>> +/* sparsemem */
>> +#define _SECTION_SIZE_BITS 30
>> +#define _MAX_PHYSMEM_BITS_LVL4 53
>> +
>> +#define STACK_BIAS 2047
>> +
>> +struct machine_specific {
>> + ulong flags;
>> + ulong userspace_top;
>> + ulong page_offset;
>> + ulong vmalloc_start;
>> + ulong vmalloc_end;
>> + ulong modules_vaddr;
>> + ulong modules_end;
>> + ulong phys_offset;
>> + ulong __exception_text_start;
>> + ulong __exception_text_end;
>> + struct pt_regs *panic_task_regs;
>> + ulong pte_protnone;
>> + ulong pte_file;
>> + uint pgd_shift;
>> + uint pud_shift;
>> + uint pmd_shift;
>> + uint ptes_per_pte;
>> +};
> Most of the values in machine_specific are in reality constants.
> Do we really gain anything colleting the various constants in a struct?
> Look like this may have been copied from an arch where much more is dynamic.
At one time it made sense. I had crash supporting older kernels with
different page cache layouts, but I didn't think it would be worth the
complexity to leave all that in there, so I pulled a lot out. I should
go a little further to simplify it. Hopefully, we're done messing with
the page table format.
>> +
>> +#define TIF_SIGPENDING (2)
>> +#define SWP_OFFSET(E) ((E) >> (13UL+8UL))
>> +#define SWP_TYPE(E) (((E) >> (13UL)) & 0xffUL)
>> +#define __swp_type(E) SWP_TYPE(E)
>> +#define __swp_offset(E) SWP_OFFSET(E)
>
> The SWP_OFFSET indirection is just obscufation - should be dropped.
> Same with SWP_TYPE.
> Maybe this is needed in generic code - but at least not in this patch.
It's this way for all the architectures, so I followed suit.
> And the 13UL is PAGE_SHIFT hardcoded - replace this with PAGE_SHIFT.
That I will fix.
>> /*
>> + * sparc64.c
>> + */
>> +#ifdef SPARC64
>> +void sparc64_init(int);
>> +void sparc64_dump_machdep_table(ulong);
>> +int sparc64_vmalloc_addr(ulong);
>> +#define display_idt_table() \
>> + error(FATAL, "The -d option is not applicable to sparc64.\n")
> Is a macro really needed?
> A static inline is preferable due to better typechecks etc.
> Not that there are much to check here - but in general.
This is copied from what other architectures do.
>> diff --git a/sparc64.c b/sparc64.c
>> new file mode 100644
>> index 0000000..7d26137
>> --- /dev/null
>> +++ b/sparc64.c
>> @@ -0,0 +1,1186 @@
>> +#ifdef SPARC64
>> +
>> +#include "defs.h"
>> +#include <stdio.h>
>> +#include <elf.h>
>> +#include <asm/ptrace.h>
>> +#include <linux/const.h>
>> +
>> +/* Things not done, debugged or tested at this point:
>> + * 1) uvtop swap handling
>> + * 2) uniform page table layout - like we had in 1st quarter of 2013
>> + * 3) and whatever can't be thought of.
>> + */
>> +#define true (1)
>> +#define false (0)
> Irk - this should be provided by compiler/glibc.
The rest of the code uses TRUE and FALSE. I don't know we do this in
lower case. I'm going to change it to be consistent.
>> +static const unsigned long not_valid_pte = ~0UL;
>> +static struct machine_specific sparc64_machine_specific;
>> +static unsigned long sparc64_ksp_offset;
>> +#define MAGIC_TT (0x1ff)
> I see this used in places like this:
> (regs->magic & ~MAGIC_TT) != PT_REGS_MAGIC
> But the name MAGIC_TT does not give much clue what this is for.
I'll come up with a better name.
> And the mix of defines, then prototypes, then (even no empty line) a define again
> does not increase readability.
Agreed.
>> +static uint page_size(void)
>> +{
>> + return machdep->pagesize;
>> +}
> I cannot see the vaule of hiding PAGE_SIZE first in a struct, and now in a static function.
> Unless this is required by code I cannot see in the patch of course.
The struct is used in generic code, but this static function is only
used once and needs to go.
>> +static void
>> +sparc64_display_machine_stats(void)
>> +{
>> + int c;
>> + 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", kt->cpus);
>> + 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());
> PAGESIZE() is a function call?
Yes, in generic code. Which really makes the above page_size()
redundant. Whoever began this port must have disliked all caps.
>
>> + fprintf(fp, " KERNEL VIRTUAL BASE: %lx\n", machdep->kvbase);
>> + fprintf(fp, " KERNEL VMALLOC BASE: %lx\n", vt->vmalloc_start);
>> + fprintf(fp, " KERNEL MODULES BASE: %lx\n", MODULES_VADDR);
>> + fprintf(fp, " KERNEL STACK SIZE: %ld\n", STACKSIZE());
> STACKSIZE is not defined. Assuming it comes from the generic part somehow.
yes
>> +static void sparc64_display_memmap(void)
>> +{
>> + unsigned long iomem_resource;
>> + unsigned long resource;
>> + unsigned long start, end, nameptr;
>> + int size = STRUCT_SIZE("resource");
>> + char *buf = GETBUF(size);
>> + char name[32];
> In the kernel work we try to avoid mixing local variable definitions
> and assignments - as code like the above is a little hard to read.
Good point. I just realized that there's a memory leak here since GETBUF
makes an allocation that is not freed.
>> +static void sparc64_cmd_mach(void)
>> +{
>> + int c;
>> + int mflag = 0;
>> +
>> + while ((c = getopt(argcnt, args, "cm")) != EOF) {
>> + switch (c) {
>> + case 'm':
>> + mflag++;
>> + sparc64_display_memmap();
>> + break;
>> + case 'c':
>> + fprintf(fp, "SPARC64: '-%c' option is not supported\n",
>> + c);
>> + break;
>> + default:
>> + argerrs++;
>> + break;
>> + }
>> + }
> Was this a better place to handle that -d flag is not supported?
This is another case where I duplicated what other architectures do. It
looks like the -d or -x flags only make sense with the -c flag, which is
not supported (as yet). Of course, if I can make the sparc code a little
clearer, I don't have follow the other arches to the letter.
>> +static int sparc64_phys_live_valid(unsigned long paddr)
>> +{
>> + unsigned int nr;
>> + int rc = false;
>> +
>> + for (nr = 0U; nr != nr_phys_ranges; nr++) {
> What is gained by 0U versus 0 here?
Nothing.
>
>> + if (paddr >= phys_ranges[nr].start &&
>> + paddr < phys_ranges[nr].end) {
>> + rc = true;
>> + break;
>> + }
>> + }
>> + return rc;
>> +}
>> +
>> +static int sparc64_phys_kdump_valid(unsigned long paddr)
>> +{
>> + return true;
>> +}
>> +
>> +static void sparc6_phys_base_live_limits(void)
>> +{
>> + if (nr_phys_ranges >= NR_PHYS_RANGES)
>> + error(FATAL, "sparc6_phys_base_live_limits: "
>> + "NR_PHYS_RANGES exceeded.\n");
>> + else if (nr_kimage_ranges >= NR_IMAGE_RANGES)
>> + error(FATAL, "sparc6_phys_base_live_limits: "
>> + "NR_IMAGE_RANGES exceeded.\n");
>> +}
>> +
>> +static void sparc64_phys_base_live_valid(void)
>> +{
>> + if (!nr_phys_ranges)
>> + error(FATAL, "No physical memory ranges.");
>> + else if (!nr_kimage_ranges)
>> + error(FATAL, "No vmlinux memory ranges.");
>> +}
>> +
>> +static void sparc64_phys_base_live(void)
>> +{
>> + char line[BUFSIZE];
>> + FILE *fp;
>> +
>> + fp = fopen("/proc/iomem", "r");
>> + if (fp == NULL)
>> + error(FATAL, "Can't open /proc/iomem. We can't proceed.");
>> +
>> + while (fgets(line, sizeof(line), fp) != 0) {
>> + unsigned long start, end;
>> + int count, consumed;
>> + char *ch;
>> +
>> + sparc6_phys_base_live_limits();
> If we exceed NR_PHYS_RANGES or NR_IMAGE_RANGES then we would fault below,
> because the execution continue. (If error() returns that is).
> Error handling looks a little ackward.
error(FATAL, ...) does not return.
>> +
>> +static int sparc64_is_linear_mapped(unsigned long vaddr)
>> +{
>> + int rc = 0;
>> +
>> + if ((vaddr & PAGE_OFFSET) == PAGE_OFFSET)
>> + rc = 1;
>> + return rc;
>
> Just do a simple:
> return (vaddr & PAGE_OFFSET) == PAGE_OFFSET;
Yeah. I'm thinking this evolved from something more complicated.
>
>> +static unsigned long fetch_page_table_level(unsigned long pte_kva,
>> + unsigned long vaddr, unsigned int shift,
>> + unsigned int mask, const char *name,
>> + int verbose)
>> +{
> Coding style nit.
> In some places the return type is on a separate line,
> other places on the same line as the function name.
> And the extra parameters would be better located aligned with the first
> parameter on the first line (using TABS and SPACES as appropriate).
> But all this is from being used to kernel style.
> General note that apply to the whole patch.
It seems that most of the crash code puts the return type on a separate
line, but it's not universally enforced. I'll fix it to be consistent.
>> +int sparc64_IS_VMALLOC_ADDR(ulong vaddr)
>> +{
>> + int ret = (vaddr >= machdep->machspec->vmalloc_start &&
>> + vaddr < machdep->machspec->vmalloc_end);
>> +
>> + return ret;
> This could be a one-liner.
> And if you insist on using a local variable then name it rc as in other palces.
okay
>
>> +}
>> +
>> +static int sparc64_dis_filter(ulong vaddr, char *inbuf, unsigned int radix)
>> +{
>> + return false;
>> +}
> Two tab indent?
oops
>
>> +{
>> + struct {struct sparc_stackf sf; struct pt_regs pr; }
>> + exception_frame_data;
> Does this really need to be inside the function body?
No. It's pretty ugly there.
>> + unsigned long exception_frame = bt->stacktop;
>> + unsigned long first_frame;
>> + struct reg_window one_down;
>> + int rc;
>> +
>> + exception_frame = exception_frame - TRACEREG_SZ - STACKFRAME_SZ;
>> + rc = readmem(exception_frame, KVADDR, &exception_frame_data,
>> + sizeof(exception_frame_data), "EF fetch.", RETURN_ON_ERROR);
>> + if (!rc)
>> + goto out;
>> + if (exception_frame_data.pr.magic != 0x57ac6c00)
> Please use PT_REGS_MAGIC. Do you need to mask out the lower 9 bits as doen in other places?
It looks like it.
>> + goto out;
>> + first_frame = exception_frame - sizeof(struct reg_window);
>> +
>> + rc = readmem(first_frame, KVADDR, &one_down, sizeof(struct reg_window),
>> + "Stack fetch.", RETURN_ON_ERROR);
>> + if (!rc)
>> + goto out;
>> + /* Extra arguments. */
>> + first_frame = first_frame - (6 * 8);
> Where did 6 * 8 suddenly come from?
I'm not sure. I'm going to have to figure out what this function is
supposed to do. :-)
>> +
>> + rc = readmem(first_frame, KVADDR, &one_down, sizeof(struct reg_window),
>> + "Stack fetch.", RETURN_ON_ERROR);
>> + if (!rc)
>> + goto out;
>> +out:
>> + return rc;
>> +}
>> +
>> +/* Need to handle hardirq and softirq stacks. */
>> +static int kstack_valid(struct bt_info *bt, unsigned long sp)
>> +{
>> + unsigned long thread_info = SIZE(thread_info);
>> + unsigned long base = bt->stackbase + thread_info;
>> + unsigned long top = bt->stacktop - sizeof(struct sparc_stackf) -
>> + sizeof(struct pt_regs);
>> + int rc = false;
>> +
>> + if (sp & (16U - 1))
>> + goto out;
> Where did 16U come from?
I'm assuming valid stack frames must be 16-byte aligned.
>> +
>> + if ((sp >= base) && (sp <= top))
>> + rc = true;
>> +out:
>> + return rc;
>> +}
>> +
>> +static void sparc64_print_eframe(struct bt_info *bt, unsigned long stack_top)
>> +{
>> + struct {struct sparc_stackf sf; struct pt_regs pr; } k_entry;
> Duplicated - was also in previous function.
Yeah. will fix.
>> +static int sparc64_is_vmalloc_mapped(unsigned long vaddr)
>> +{
>> + struct machine_specific *ms = &sparc64_machine_specific;
>> + int rc = 0;
>> +
>> + /* We exclude OBP range whose TTEs were captured by kernel in
>> + * early boot. It is possible to fetch these but for what purpose?
>> + */
> Comment says OBP but code used modules_vaddr / modules_end, vmalloc_start, vmalloc_end
That comment clearly doesn't belong.
>
>> + if ((vaddr >= ms->modules_vaddr && vaddr < ms->modules_end) ||
>> + (vaddr >= ms->vmalloc_start && vaddr < ms->vmalloc_end))
>> + rc = 1;
>> + return rc;
>> +}
>> +
>> +static int sparc64_is_kvaddr(ulong vaddr)
>> +{
>> + int rc = kimage_va_range(vaddr);
>> +
>> + if (rc)
>> + goto out;
>> + rc = sparc64_is_linear_mapped(vaddr);
>> + if (rc)
>> + goto out;
>> + rc = sparc64_is_vmalloc_mapped(vaddr);
>> +out:
>> + return rc;
>> +}
> Use goto for error handling.
> The above is not easy to read/parse.
I may just replace this with:
return kimage_va_range(vaddr) ||
sparc64_is_linear_mapped(vaddr) ||
sparc64_is_vmalloc_mapped(vaddr);
>
>> +
>> +static int sparc64_kvtop(struct task_context *tc, ulong vaddr,
>> + physaddr_t *paddr, int verbose)
>> +{
>> + unsigned long phys_addr;
>> + int rc = false;
>> +
>> + if (kimage_va_range(vaddr))
>> + phys_addr = kimage_va_translate(vaddr);
>> + else if (sparc64_is_vmalloc_mapped(vaddr)) {
>> + phys_addr = sparc64_vmalloc_translate(vaddr, verbose);
>> + if (phys_addr == not_valid_pte)
>> + goto out;
>> + } else if (sparc64_is_linear_mapped(vaddr))
>> + phys_addr = sparc64_linear_translate(vaddr);
>> + else {
>> + error(WARNING,
>> + "This is an invalid kernel virtual address=0x%lx.",
>> + vaddr);
>> + goto out;
>> + }
> Coding style nit.
> If you need {} then use it for all statements, also single liners.
okay
>
> So use:
> if (foo()) {
> bar();
> } else {
> baz();
> baz2();
> }
>
>> diff --git a/task.c b/task.c
>> index 7b01951..f21d0f8 100644
>> --- a/task.c
>> +++ b/task.c
>> @@ -2368,7 +2369,11 @@ store_context(struct task_context *tc, ulong task, char *tp)
>>
>> tc->pid = (ulong)(*pid_addr);
>> strlcpy(tc->comm, comm_addr, TASK_COMM_LEN);
>> - tc->processor = *processor_addr;
>> +#ifdef SPARC64
>> + tc->processor = *(unsigned short *)processor_addr;
>> +#else
>> + tc->processor = *processor_addr;
>> +#endif
> This looks like it is papering over something that needs a proper fix.
> And it does not look sparc64 specific, so should be a separate patch.
Only sparc has a 16-bit thread_info->cpu. A generic fix would be little
more complicated, but would avoid the ifdef.
>
>> tc->ptask = *parent_addr;
>> tc->mm_struct = *mm_addr;
>> tc->task = task;
>> @@ -5266,8 +5271,15 @@ task_flags(ulong task)
>>
>> fill_task_struct(task);
>>
>> - flags = tt->last_task_read ?
>> - ULONG(tt->task_struct + OFFSET(task_struct_flags)) : 0;
>> + if (tt->last_task_read) {
>> + if (SIZE(task_struct_flags) == sizeof(unsigned int))
>> + flags = UINT(tt->task_struct +
>> + OFFSET(task_struct_flags));
>> + else
>> + flags = ULONG(tt->task_struct +
>> + OFFSET(task_struct_flags));
>> + } else
>> + flags = 0;
> This also looks like it is paerign over something that should see a proper fix.
> And it does not look sparc64 specific, so should be in a separate patch.
It's not sparc64-specific, but fixes a generic bug I found with sparc64.
This is the proper fix because crash can't hard-code the type of
task_struct->flags.
More information about the Crash-utility
mailing list