[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