Blame s390.c

Packit bf408e
/* s390.c - core analysis suite
Packit bf408e
 *
Packit bf408e
 * Copyright (C) 2001, 2002 Mission Critical Linux, Inc.
Packit bf408e
 * Copyright (C) 2002-2006, 2009-2010, 2012-2014 David Anderson
Packit bf408e
 * Copyright (C) 2002-2006, 2009-2010, 2012-2014 Red Hat, Inc. All rights reserved.
Packit bf408e
 * Copyright (C) 2005, 2006, 2010 Michael Holzheu, IBM Corporation
Packit bf408e
 *
Packit bf408e
 * This program is free software; you can redistribute it and/or modify
Packit bf408e
 * it under the terms of the GNU General Public License as published by
Packit bf408e
 * the Free Software Foundation; either version 2 of the License, or
Packit bf408e
 * (at your option) any later version.
Packit bf408e
 *
Packit bf408e
 * This program is distributed in the hope that it will be useful,
Packit bf408e
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit bf408e
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit bf408e
 * GNU General Public License for more details.
Packit bf408e
 */
Packit bf408e
#ifdef S390 
Packit bf408e
#include "defs.h"
Packit bf408e
Packit bf408e
#define S390_WORD_SIZE    4
Packit bf408e
#define S390_ADDR_MASK    0x7fffffff
Packit bf408e
Packit bf408e
#define S390_PMD_BASE_MASK      (~((1UL<<6)-1))
Packit bf408e
#define S390_PT_BASE_MASK       S390_PMD_BASE_MASK
Packit bf408e
#define S390_PAGE_BASE_MASK     (~((1UL<<12)-1))
Packit bf408e
Packit bf408e
/* Flags used in entries of page dirs and page tables.
Packit bf408e
 */
Packit bf408e
#define S390_PAGE_PRESENT       0x001    /* set: loaded in physical memory
Packit bf408e
                                         * clear: not loaded in physical mem */
Packit bf408e
#define S390_RO_S390            0x200    /* HW read-only */
Packit bf408e
#define S390_PAGE_INVALID       0x400    /* HW invalid */
Packit bf408e
#define S390_PAGE_INVALID_MASK  0x601ULL /* for linux 2.6 */
Packit bf408e
#define S390_PAGE_INVALID_NONE  0x401ULL /* for linux 2.6 */
Packit bf408e
Packit bf408e
#define S390_PTE_INVALID_MASK   0x80000900
Packit bf408e
#define S390_PTE_INVALID(x) ((x) & S390_PTE_INVALID_MASK)
Packit bf408e
Packit bf408e
#define INT_STACK_SIZE    STACKSIZE() // can be 4096 or 8192
Packit bf408e
#define KERNEL_STACK_SIZE STACKSIZE() // can be 4096 or 8192
Packit bf408e
Packit bf408e
#define LOWCORE_SIZE 4096
Packit bf408e
Packit bf408e
/*
Packit bf408e
 * declarations of static functions
Packit bf408e
 */
Packit bf408e
static void s390_print_lowcore(char*, struct bt_info*,int);
Packit bf408e
static int s390_kvtop(struct task_context *, ulong, physaddr_t *, int);
Packit bf408e
static int s390_uvtop(struct task_context *, ulong, physaddr_t *, int);
Packit bf408e
static int s390_vtop(unsigned long, ulong, physaddr_t*, int);
Packit bf408e
static ulong s390_vmalloc_start(void);
Packit bf408e
static int s390_is_task_addr(ulong);
Packit bf408e
static int s390_verify_symbol(const char *, ulong, char type);
Packit bf408e
static ulong s390_get_task_pgd(ulong);
Packit bf408e
static int s390_translate_pte(ulong, void *, ulonglong);
Packit bf408e
static ulong s390_processor_speed(void);
Packit bf408e
static int s390_eframe_search(struct bt_info *);
Packit bf408e
static void s390_back_trace_cmd(struct bt_info *);
Packit bf408e
static void s390_get_stack_frame(struct bt_info *, ulong *, ulong *);
Packit bf408e
static int s390_dis_filter(ulong, char *, unsigned int);
Packit bf408e
static void s390_cmd_mach(void);
Packit bf408e
static int s390_get_smp_cpus(void);
Packit bf408e
static void s390_display_machine_stats(void);
Packit bf408e
static void s390_dump_line_number(ulong);
Packit bf408e
static struct line_number_hook s390_line_number_hooks[];
Packit bf408e
static int s390_is_uvaddr(ulong, struct task_context *);
Packit bf408e
Packit bf408e
/*
Packit bf408e
 * struct lowcore name (old: "_lowcore", new: "lowcore")
Packit bf408e
 */
Packit bf408e
static char *lc_struct;
Packit bf408e
Packit bf408e
/*
Packit bf408e
 * Initialize member offsets
Packit bf408e
 */
Packit bf408e
static void s390_offsets_init(void)
Packit bf408e
{
Packit bf408e
	if (STRUCT_EXISTS("lowcore"))
Packit bf408e
		lc_struct = "lowcore";
Packit bf408e
	else
Packit bf408e
		lc_struct = "_lowcore";
Packit bf408e
	if (MEMBER_EXISTS(lc_struct, "st_status_fixed_logout"))
Packit bf408e
		MEMBER_OFFSET_INIT(s390_lowcore_psw_save_area, lc_struct,
Packit bf408e
				   "st_status_fixed_logout");
Packit bf408e
	else
Packit bf408e
		MEMBER_OFFSET_INIT(s390_lowcore_psw_save_area, lc_struct,
Packit bf408e
				   "psw_save_area");
Packit bf408e
}
Packit bf408e
Packit bf408e
/*
Packit bf408e
 *  Do all necessary machine-specific setup here.  This is called several
Packit bf408e
 *  times during initialization.
Packit bf408e
 */
Packit bf408e
void
Packit bf408e
s390_init(int when)
Packit bf408e
{
Packit bf408e
	switch (when)
Packit bf408e
	{
Packit bf408e
	case PRE_SYMTAB:
Packit bf408e
		machdep->verify_symbol = s390_verify_symbol;
Packit bf408e
		if (pc->flags & KERNEL_DEBUG_QUERY)
Packit bf408e
			return;
Packit bf408e
		machdep->pagesize = memory_page_size();
Packit bf408e
		machdep->pageshift = ffs(machdep->pagesize) - 1;
Packit bf408e
		machdep->pageoffset = machdep->pagesize - 1;
Packit bf408e
		machdep->pagemask = ~((ulonglong)machdep->pageoffset);
Packit bf408e
		// machdep->stacksize = machdep->pagesize * 2;
Packit bf408e
		if ((machdep->pgd = (char *)malloc(SEGMENT_TABLE_SIZE)) == NULL)
Packit bf408e
			error(FATAL, "cannot malloc pgd space.");
Packit bf408e
		machdep->pmd = machdep->pgd;
Packit bf408e
		if ((machdep->ptbl = (char *)malloc(PAGESIZE())) == NULL)
Packit bf408e
			error(FATAL, "cannot malloc ptbl space.");
Packit bf408e
		machdep->last_pgd_read = 0;
Packit bf408e
		machdep->last_pmd_read = 0;
Packit bf408e
		machdep->last_ptbl_read = 0;
Packit bf408e
		machdep->verify_paddr = generic_verify_paddr;
Packit bf408e
		machdep->ptrs_per_pgd = PTRS_PER_PGD;
Packit bf408e
		break;
Packit bf408e
Packit bf408e
	case PRE_GDB:
Packit bf408e
		machdep->kvbase = 0;
Packit bf408e
		machdep->identity_map_base = 0;
Packit bf408e
		machdep->is_kvaddr =  generic_is_kvaddr;
Packit bf408e
		machdep->is_uvaddr =  s390_is_uvaddr;
Packit bf408e
		machdep->eframe_search = s390_eframe_search;
Packit bf408e
		machdep->back_trace = s390_back_trace_cmd;
Packit bf408e
		machdep->processor_speed = s390_processor_speed;
Packit bf408e
		machdep->uvtop = s390_uvtop;
Packit bf408e
		machdep->kvtop = s390_kvtop;
Packit bf408e
		machdep->get_task_pgd = s390_get_task_pgd;
Packit bf408e
		machdep->get_stack_frame = s390_get_stack_frame;
Packit bf408e
		machdep->get_stackbase = generic_get_stackbase;
Packit bf408e
		machdep->get_stacktop = generic_get_stacktop;
Packit bf408e
		machdep->translate_pte = s390_translate_pte;
Packit bf408e
		machdep->memory_size = generic_memory_size;
Packit bf408e
		machdep->is_task_addr = s390_is_task_addr;
Packit bf408e
		machdep->dis_filter = s390_dis_filter;
Packit bf408e
		machdep->cmd_mach = s390_cmd_mach;
Packit bf408e
		machdep->get_smp_cpus = s390_get_smp_cpus;
Packit bf408e
		machdep->line_number_hooks = s390_line_number_hooks;
Packit bf408e
		machdep->value_to_symbol = generic_machdep_value_to_symbol;
Packit bf408e
		machdep->init_kernel_pgd = NULL;
Packit bf408e
		vt->flags |= COMMON_VADDR;
Packit bf408e
		break;
Packit bf408e
Packit bf408e
	case POST_GDB:
Packit bf408e
		if (symbol_exists("irq_desc"))
Packit bf408e
			ARRAY_LENGTH_INIT(machdep->nr_irqs, irq_desc,
Packit bf408e
				"irq_desc", NULL, 0);
Packit bf408e
		else if (kernel_symbol_exists("nr_irqs"))
Packit bf408e
			get_symbol_data("nr_irqs", sizeof(unsigned int),
Packit bf408e
				&machdep->nr_irqs);
Packit bf408e
		else
Packit bf408e
			machdep->nr_irqs = 0;
Packit bf408e
Packit bf408e
		machdep->vmalloc_start = s390_vmalloc_start;
Packit bf408e
		machdep->dump_irq = generic_dump_irq;
Packit bf408e
		if (!machdep->hz)
Packit bf408e
			machdep->hz = HZ;
Packit bf408e
		machdep->section_size_bits = _SECTION_SIZE_BITS;
Packit bf408e
		machdep->max_physmem_bits = _MAX_PHYSMEM_BITS;
Packit bf408e
		s390_offsets_init();
Packit bf408e
		break;
Packit bf408e
Packit bf408e
	case POST_INIT:
Packit bf408e
		break;
Packit bf408e
	}
Packit bf408e
}
Packit bf408e
Packit bf408e
/*
Packit bf408e
 * Dump machine dependent information
Packit bf408e
 */
Packit bf408e
void
Packit bf408e
s390_dump_machdep_table(ulong arg)
Packit bf408e
{
Packit bf408e
	int others; 
Packit bf408e
 
Packit bf408e
	others = 0;
Packit bf408e
	fprintf(fp, "              flags: %lx (", machdep->flags);
Packit bf408e
	if (machdep->flags & KSYMS_START)
Packit bf408e
		fprintf(fp, "%sKSYMS_START", others++ ? "|" : "");
Packit bf408e
	fprintf(fp, ")\n");
Packit bf408e
Packit bf408e
	fprintf(fp, "             kvbase: %lx\n", machdep->kvbase);
Packit bf408e
	fprintf(fp, "  identity_map_base: %lx\n", machdep->kvbase);
Packit bf408e
	fprintf(fp, "           pagesize: %d\n", machdep->pagesize);
Packit bf408e
	fprintf(fp, "          pageshift: %d\n", machdep->pageshift);
Packit bf408e
	fprintf(fp, "           pagemask: %llx\n", machdep->pagemask);
Packit bf408e
	fprintf(fp, "         pageoffset: %lx\n", machdep->pageoffset);
Packit bf408e
	fprintf(fp, "          stacksize: %ld\n", machdep->stacksize);
Packit bf408e
	fprintf(fp, "                 hz: %d\n", machdep->hz);
Packit bf408e
	fprintf(fp, "                mhz: %ld\n", machdep->mhz);
Packit bf408e
	fprintf(fp, "            memsize: %lld (0x%llx)\n", 
Packit bf408e
		(ulonglong)machdep->memsize, (ulonglong)machdep->memsize);
Packit bf408e
	fprintf(fp, "               bits: %d\n", machdep->bits);
Packit bf408e
	fprintf(fp, "            nr_irqs: %d\n", machdep->nr_irqs);
Packit bf408e
	fprintf(fp, "      eframe_search: s390_eframe_search()\n");
Packit bf408e
	fprintf(fp, "         back_trace: s390_back_trace_cmd()\n");
Packit bf408e
	fprintf(fp, "    processor_speed: s390_processor_speed()\n");
Packit bf408e
	fprintf(fp, "              uvtop: s390_uvtop()\n");
Packit bf408e
	fprintf(fp, "              kvtop: s390_kvtop()\n");
Packit bf408e
	fprintf(fp, "       get_task_pgd: s390_get_task_pgd()\n");
Packit bf408e
	fprintf(fp, "           dump_irq: generic_dump_irq()\n");
Packit bf408e
	fprintf(fp, "    get_stack_frame: s390_get_stack_frame()\n");
Packit bf408e
	fprintf(fp, "      get_stackbase: generic_get_stackbase()\n");
Packit bf408e
	fprintf(fp, "       get_stacktop: generic_get_stacktop()\n");
Packit bf408e
	fprintf(fp, "      translate_pte: s390_translate_pte()\n");
Packit bf408e
	fprintf(fp, "        memory_size: generic_memory_size()\n");
Packit bf408e
	fprintf(fp, "      vmalloc_start: s390_vmalloc_start()\n");
Packit bf408e
	fprintf(fp, "       is_task_addr: s390_is_task_addr()\n");
Packit bf408e
	fprintf(fp, "      verify_symbol: s390_verify_symbol()\n");
Packit bf408e
	fprintf(fp, "         dis_filter: s390_dis_filter()\n");
Packit bf408e
	fprintf(fp, "           cmd_mach: s390_cmd_mach()\n");
Packit bf408e
	fprintf(fp, "       get_smp_cpus: s390_get_smp_cpus()\n");
Packit bf408e
	fprintf(fp, "          is_kvaddr: generic_is_kvaddr()\n");
Packit bf408e
	fprintf(fp, "          is_uvaddr: s390_is_uvaddr()\n");
Packit bf408e
	fprintf(fp, "       verify_paddr: generic_verify_paddr()\n");
Packit bf408e
	fprintf(fp, "    init_kernel_pgd: NULL\n");
Packit bf408e
	fprintf(fp, "    value_to_symbol: generic_machdep_value_to_symbol()\n");
Packit bf408e
	fprintf(fp, "  line_number_hooks: s390_line_number_hooks\n");
Packit bf408e
	fprintf(fp, "      last_pgd_read: %lx\n", machdep->last_pgd_read);
Packit bf408e
	fprintf(fp, "      last_pmd_read: %lx\n", machdep->last_pmd_read);
Packit bf408e
	fprintf(fp, "     last_ptbl_read: %lx\n", machdep->last_ptbl_read);
Packit bf408e
	fprintf(fp, "                pgd: %lx\n", (ulong)machdep->pgd);
Packit bf408e
	fprintf(fp, "                pmd: %lx\n", (ulong)machdep->pmd);
Packit bf408e
	fprintf(fp, "               ptbl: %lx\n", (ulong)machdep->ptbl);
Packit bf408e
	fprintf(fp, "       ptrs_per_pgd: %d\n", machdep->ptrs_per_pgd);
Packit bf408e
	fprintf(fp, "   max_physmem_bits: %ld\n", machdep->max_physmem_bits);
Packit bf408e
	fprintf(fp, "  section_size_bits: %ld\n", machdep->section_size_bits);
Packit bf408e
	fprintf(fp, "           machspec: %lx\n", (ulong)machdep->machspec);
Packit bf408e
}
Packit bf408e
Packit bf408e
/*
Packit bf408e
 * Check if address is in context's address space
Packit bf408e
 */
Packit bf408e
static int 
Packit bf408e
s390_is_uvaddr(ulong vaddr, struct task_context *tc)
Packit bf408e
{
Packit bf408e
	return IN_TASK_VMA(tc->task, vaddr);
Packit bf408e
}
Packit bf408e
Packit bf408e
/*
Packit bf408e
 *  Translates a user virtual address to its physical address
Packit bf408e
 */
Packit bf408e
static int
Packit bf408e
s390_uvtop(struct task_context *tc, ulong vaddr, physaddr_t *paddr, int verbose)
Packit bf408e
{
Packit bf408e
	unsigned long pgd_base;
Packit bf408e
	readmem(tc->mm_struct + OFFSET(mm_struct_pgd), KVADDR, 
Packit bf408e
		&pgd_base,sizeof(long), "pgd_base",FAULT_ON_ERROR);
Packit bf408e
	return s390_vtop(pgd_base, vaddr, paddr, verbose);
Packit bf408e
}
Packit bf408e
Packit bf408e
/*
Packit bf408e
 *  Translates a kernel virtual address to its physical address
Packit bf408e
 */
Packit bf408e
static int
Packit bf408e
s390_kvtop(struct task_context *tc, ulong vaddr, physaddr_t *paddr, int verbose)
Packit bf408e
{
Packit bf408e
	unsigned long pgd_base;
Packit bf408e
Packit bf408e
	if (!IS_KVADDR(vaddr)){
Packit bf408e
		*paddr = 0;
Packit bf408e
		return FALSE;
Packit bf408e
	}
Packit bf408e
Packit bf408e
	if (!vt->vmalloc_start) {
Packit bf408e
	       *paddr = VTOP(vaddr);
Packit bf408e
	       return TRUE;
Packit bf408e
	}
Packit bf408e
Packit bf408e
	if (!IS_VMALLOC_ADDR(vaddr)) {
Packit bf408e
	       *paddr = VTOP(vaddr);
Packit bf408e
	       return TRUE;
Packit bf408e
	}
Packit bf408e
Packit bf408e
	pgd_base = (unsigned long)vt->kernel_pgd[0];
Packit bf408e
	return s390_vtop(pgd_base, vaddr, paddr, verbose);
Packit bf408e
}
Packit bf408e
Packit bf408e
/*
Packit bf408e
 * Check if page is mapped
Packit bf408e
 */
Packit bf408e
static inline int 
Packit bf408e
s390_pte_present(unsigned long x)
Packit bf408e
{
Packit bf408e
	if(THIS_KERNEL_VERSION >= LINUX(2,6,0)) {
Packit bf408e
		return !((x) & S390_PAGE_INVALID) ||
Packit bf408e
			((x) & S390_PAGE_INVALID_MASK)==S390_PAGE_INVALID_NONE;
Packit bf408e
	} else {
Packit bf408e
		return((x) & S390_PAGE_PRESENT);
Packit bf408e
	}
Packit bf408e
}
Packit bf408e
Packit bf408e
/*
Packit bf408e
 * page table traversal functions
Packit bf408e
 */
Packit bf408e
Packit bf408e
/* Segment table traversal function */
Packit bf408e
static ulong _kl_sg_table_deref_s390(ulong vaddr, ulong table, int len)
Packit bf408e
{
Packit bf408e
	ulong offset, entry;
Packit bf408e
Packit bf408e
	offset = ((vaddr >> 20) & 0x7ffUL) * 4;
Packit bf408e
	if (offset >= (len + 1)*64)
Packit bf408e
		/* Offset is over the table limit. */
Packit bf408e
		return 0;
Packit bf408e
	readmem(table + offset, KVADDR, &entry, sizeof(entry), "entry",
Packit bf408e
		FAULT_ON_ERROR);
Packit bf408e
Packit bf408e
	/*
Packit bf408e
	 * Check if the segment table entry could be read and doesn't have
Packit bf408e
	 * any of the reserved bits set.
Packit bf408e
	 */
Packit bf408e
	if (entry & 0x80000000UL)
Packit bf408e
		return 0;
Packit bf408e
	/* Check if the segment table entry has the invalid bit set. */
Packit bf408e
	if (entry & 0x40UL)
Packit bf408e
		return 0;
Packit bf408e
	/* Segment table entry is valid and well formed. */
Packit bf408e
	return entry;
Packit bf408e
}
Packit bf408e
Packit bf408e
/* Page table traversal function */
Packit bf408e
static ulong _kl_pg_table_deref_s390(ulong vaddr, ulong table, int len)
Packit bf408e
{
Packit bf408e
	ulong offset, entry;
Packit bf408e
Packit bf408e
	offset = ((vaddr >> 12) & 0xffUL) * 4;
Packit bf408e
	if (offset >= (len + 1)*64)
Packit bf408e
		/* Offset is over the table limit. */
Packit bf408e
		return 0;
Packit bf408e
	readmem(table + offset, KVADDR, &entry, sizeof(entry), "entry",
Packit bf408e
		FAULT_ON_ERROR);
Packit bf408e
	/*
Packit bf408e
	 * Check if the page table entry could be read and doesn't have
Packit bf408e
	 * any of the reserved bits set.
Packit bf408e
	 */
Packit bf408e
	if (entry & 0x80000900UL)
Packit bf408e
		return 0;
Packit bf408e
	/* Check if the page table entry has the invalid bit set. */
Packit bf408e
	if (entry & 0x400UL)
Packit bf408e
		return 0;
Packit bf408e
	/* Page table entry is valid and well formed. */
Packit bf408e
	return entry;
Packit bf408e
}
Packit bf408e
Packit bf408e
/* lookup virtual address in page tables */
Packit bf408e
static int
Packit bf408e
s390_vtop(unsigned long table, ulong vaddr, physaddr_t *phys_addr, int verbose)
Packit bf408e
{
Packit bf408e
	ulong entry, paddr;
Packit bf408e
	int len;
Packit bf408e
Packit bf408e
	/*
Packit bf408e
	 * Get the segment table entry.
Packit bf408e
	 * We assume that the segment table length field in the asce
Packit bf408e
	 * is set to the maximum value of 127 (which translates to
Packit bf408e
	 * a segment table with 2048 entries) and that the addressing
Packit bf408e
	 * mode is 31 bit.
Packit bf408e
	 */
Packit bf408e
	entry = _kl_sg_table_deref_s390(vaddr, table, 127);
Packit bf408e
	if (!entry)
Packit bf408e
		return FALSE;
Packit bf408e
	table = entry & 0x7ffffc00UL;
Packit bf408e
	len = entry & 0xfUL;
Packit bf408e
Packit bf408e
	/* Get the page table entry */
Packit bf408e
	entry = _kl_pg_table_deref_s390(vaddr, table, len);
Packit bf408e
	if (!entry)
Packit bf408e
		return FALSE;
Packit bf408e
Packit bf408e
	/* Isolate the page origin from the page table entry. */
Packit bf408e
	paddr = entry & 0x7ffff000UL;
Packit bf408e
Packit bf408e
	/* Add the page offset and return the final value. */
Packit bf408e
	*phys_addr = paddr + (vaddr & 0xfffUL);
Packit bf408e
Packit bf408e
	return TRUE;
Packit bf408e
}
Packit bf408e
Packit bf408e
/*
Packit bf408e
 *  Determine where vmalloc'd memory starts.
Packit bf408e
 */
Packit bf408e
static ulong
Packit bf408e
s390_vmalloc_start(void)
Packit bf408e
{
Packit bf408e
	unsigned long highmem_addr,high_memory;
Packit bf408e
	highmem_addr=symbol_value("high_memory");
Packit bf408e
       	readmem(highmem_addr, PHYSADDR, &high_memory,sizeof(long),
Packit bf408e
		"highmem",FAULT_ON_ERROR);
Packit bf408e
	return high_memory;
Packit bf408e
}
Packit bf408e
Packit bf408e
/*
Packit bf408e
 * Check if address can be a valid task_struct
Packit bf408e
 */
Packit bf408e
static int
Packit bf408e
s390_is_task_addr(ulong task)
Packit bf408e
{
Packit bf408e
	if (tt->flags & THREAD_INFO)
Packit bf408e
		return IS_KVADDR(task);
Packit bf408e
	else
Packit bf408e
		return (IS_KVADDR(task) && (ALIGNED_STACK_OFFSET(task) == 0));
Packit bf408e
}
Packit bf408e
Packit bf408e
/*
Packit bf408e
 * return MHz - unfortunately it is not possible to get this on linux 
Packit bf408e
 *              for zSeries
Packit bf408e
 */
Packit bf408e
static ulong
Packit bf408e
s390_processor_speed(void)
Packit bf408e
{
Packit bf408e
	return 0;
Packit bf408e
}
Packit bf408e
Packit bf408e
/*
Packit bf408e
 *  Accept or reject a symbol from the kernel namelist.
Packit bf408e
 */
Packit bf408e
static int
Packit bf408e
s390_verify_symbol(const char *name, ulong value, char type)
Packit bf408e
{
Packit bf408e
	int i;
Packit bf408e
Packit bf408e
	if (CRASHDEBUG(8) && name && strlen(name))
Packit bf408e
		fprintf(fp, "%08lx %s\n", value, name);
Packit bf408e
Packit bf408e
	if (STREQ(name, "startup") || STREQ(name, "_stext"))
Packit bf408e
		machdep->flags |= KSYMS_START;
Packit bf408e
Packit bf408e
	if (!name || !strlen(name) || !(machdep->flags & KSYMS_START))
Packit bf408e
		return FALSE;
Packit bf408e
Packit bf408e
	if ((type == 'A') && STRNEQ(name, "__crc_"))
Packit bf408e
		return FALSE;
Packit bf408e
Packit bf408e
	if (STREQ(name, "Letext") || STREQ(name, "gcc2_compiled."))
Packit bf408e
		return FALSE;
Packit bf408e
Packit bf408e
	/* reject L2^B symbols */
Packit bf408e
	if (strstr(name, "L2\002") == name)
Packit bf408e
	    	return FALSE;
Packit bf408e
Packit bf408e
	/* throw away all symbols containing a '.' */
Packit bf408e
	for(i = 0; i < strlen(name);i++){
Packit bf408e
		if(name[i] == '.')
Packit bf408e
			return FALSE;
Packit bf408e
	}
Packit bf408e
Packit bf408e
	return TRUE;
Packit bf408e
}
Packit bf408e
Packit bf408e
/*
Packit bf408e
 *  Get the relevant page directory pointer from a task structure.
Packit bf408e
 */
Packit bf408e
static ulong
Packit bf408e
s390_get_task_pgd(ulong task)
Packit bf408e
{
Packit bf408e
	return (error(FATAL, "s390_get_task_pgd: TBD\n"));
Packit bf408e
}
Packit bf408e
Packit bf408e
/*
Packit bf408e
 *  Translate a PTE, returning TRUE if the page is present.
Packit bf408e
 *  If a physaddr pointer is passed in, don't print anything.
Packit bf408e
 */
Packit bf408e
static int
Packit bf408e
s390_translate_pte(ulong pte, void *physaddr, ulonglong unused)
Packit bf408e
{
Packit bf408e
	char *arglist[MAXARGS];
Packit bf408e
	char buf[BUFSIZE];
Packit bf408e
	char buf2[BUFSIZE];
Packit bf408e
	char buf3[BUFSIZE];
Packit bf408e
	char ptebuf[BUFSIZE];
Packit bf408e
	int c,len1,len2,len3;
Packit bf408e
Packit bf408e
	if(S390_PTE_INVALID(pte)){
Packit bf408e
		fprintf(fp,"PTE is invalid\n");
Packit bf408e
		return FALSE;
Packit bf408e
	}
Packit bf408e
Packit bf408e
	if(physaddr)
Packit bf408e
		*((ulong *)physaddr) = pte & S390_PAGE_BASE_MASK;
Packit bf408e
Packit bf408e
	if(!s390_pte_present(pte)){
Packit bf408e
		swap_location(pte, buf);
Packit bf408e
		if ((c = parse_line(buf, arglist)) != 3)
Packit bf408e
			error(FATAL, "cannot determine swap location\n");
Packit bf408e
Packit bf408e
		sprintf(ptebuf, "%lx", pte);
Packit bf408e
		len1 = MAX(strlen(ptebuf), strlen("PTE"));
Packit bf408e
		len2 = MAX(strlen(arglist[0]), strlen("SWAP"));
Packit bf408e
		len3 = MAX(strlen(arglist[2]), strlen("OFFSET"));
Packit bf408e
Packit bf408e
		fprintf(fp, "%s  %s  %s\n",
Packit bf408e
			mkstring(ptebuf, len1, CENTER|LJUST, "PTE"),
Packit bf408e
			mkstring(buf2, len2, CENTER|LJUST, "SWAP"),
Packit bf408e
			mkstring(buf3, len3, CENTER|LJUST, "OFFSET"));
Packit bf408e
Packit bf408e
		sprintf(ptebuf, "%lx", pte);
Packit bf408e
		strcpy(buf2, arglist[0]);
Packit bf408e
		strcpy(buf3, arglist[2]);
Packit bf408e
		fprintf(fp, "%s  %s  %s\n",
Packit bf408e
			mkstring(ptebuf, len1, CENTER|RJUST, NULL),
Packit bf408e
			mkstring(buf2, len2, CENTER|RJUST, NULL),
Packit bf408e
			mkstring(buf3, len3, CENTER|RJUST, NULL));
Packit bf408e
		return FALSE;
Packit bf408e
	}
Packit bf408e
	fprintf(fp,"PTE      PHYSICAL  FLAGS\n");
Packit bf408e
	fprintf(fp,"%08lx %08lx",pte, pte & S390_PAGE_BASE_MASK);
Packit bf408e
	fprintf(fp,"  (");
Packit bf408e
	if(pte & S390_PAGE_INVALID)
Packit bf408e
		fprintf(fp,"INVALID ");
Packit bf408e
	if(pte & S390_RO_S390)
Packit bf408e
		fprintf(fp,"PROTECTION");
Packit bf408e
	fprintf(fp,")");
Packit bf408e
	return TRUE;
Packit bf408e
}
Packit bf408e
Packit bf408e
/*
Packit bf408e
 *  Look for likely exception frames in a stack.
Packit bf408e
 */
Packit bf408e
static int 
Packit bf408e
s390_eframe_search(struct bt_info *bt)
Packit bf408e
{
Packit bf408e
	if(bt->flags & BT_EFRAME_SEARCH2)
Packit bf408e
		return (error(FATAL, 
Packit bf408e
		     "Option '-E' is not implemented for this architecture\n"));
Packit bf408e
	else
Packit bf408e
		return (error(FATAL, 
Packit bf408e
		     "Option '-e' is not implemented for this architecture\n"));
Packit bf408e
}
Packit bf408e
Packit bf408e
/*
Packit bf408e
 * returns cpu number of task
Packit bf408e
 */ 
Packit bf408e
static int 
Packit bf408e
s390_cpu_of_task(unsigned long task)
Packit bf408e
{
Packit bf408e
	int cpu;
Packit bf408e
Packit bf408e
       if(VALID_MEMBER(task_struct_processor)){
Packit bf408e
                /* linux 2.4 */
Packit bf408e
                readmem(task + OFFSET(task_struct_processor),KVADDR,
Packit bf408e
                        &cpu, sizeof(cpu), "task_struct_processor",
Packit bf408e
                        FAULT_ON_ERROR);
Packit bf408e
        } else {
Packit bf408e
		char thread_info[8192];
Packit bf408e
		unsigned long thread_info_addr;
Packit bf408e
		readmem(task + OFFSET(task_struct_thread_info),KVADDR,
Packit bf408e
			&thread_info_addr, sizeof(thread_info_addr),
Packit bf408e
			"thread info addr", FAULT_ON_ERROR);
Packit bf408e
		readmem(thread_info_addr,KVADDR,thread_info,sizeof(thread_info),
Packit bf408e
			"thread info", FAULT_ON_ERROR);
Packit bf408e
		cpu = *((int*) &thread_info[OFFSET(thread_info_cpu)]);
Packit bf408e
	}
Packit bf408e
	return cpu;
Packit bf408e
}
Packit bf408e
Packit bf408e
/*
Packit bf408e
 * returns true, if task of bt currently is executed by a cpu
Packit bf408e
 */ 
Packit bf408e
static int 
Packit bf408e
s390_has_cpu(struct bt_info *bt)
Packit bf408e
{
Packit bf408e
	int cpu = bt->tc->processor;
Packit bf408e
Packit bf408e
	if (is_task_active(bt->task) && (kt->cpu_flags[cpu] & ONLINE_MAP))
Packit bf408e
		return TRUE;
Packit bf408e
	else
Packit bf408e
		return FALSE;
Packit bf408e
}
Packit bf408e
Packit bf408e
/*
Packit bf408e
 * read lowcore for cpu
Packit bf408e
 */
Packit bf408e
static void
Packit bf408e
s390_get_lowcore(int cpu, char* lowcore)
Packit bf408e
{
Packit bf408e
	unsigned long lowcore_array,lowcore_ptr;
Packit bf408e
Packit bf408e
	lowcore_array = symbol_value("lowcore_ptr");
Packit bf408e
	readmem(lowcore_array + cpu * S390_WORD_SIZE,KVADDR,
Packit bf408e
		&lowcore_ptr, sizeof(long), "lowcore_ptr", FAULT_ON_ERROR);
Packit bf408e
	readmem(lowcore_ptr, KVADDR, lowcore, LOWCORE_SIZE, "lowcore", 
Packit bf408e
		FAULT_ON_ERROR);
Packit bf408e
}
Packit bf408e
Packit bf408e
/*
Packit bf408e
 * Read interrupt stack (either "async_stack" or "panic_stack");
Packit bf408e
 */
Packit bf408e
static void s390_get_int_stack(char *stack_name, char* lc, char* int_stack,
Packit bf408e
			       unsigned long* start, unsigned long* end)
Packit bf408e
{
Packit bf408e
	unsigned long stack_addr;
Packit bf408e
Packit bf408e
	if (!MEMBER_EXISTS(lc_struct, stack_name))
Packit bf408e
		return;
Packit bf408e
	stack_addr = ULONG(lc + MEMBER_OFFSET(lc_struct, stack_name));
Packit bf408e
	if (stack_addr == 0)
Packit bf408e
		return;
Packit bf408e
	readmem(stack_addr - INT_STACK_SIZE, KVADDR, int_stack,
Packit bf408e
		INT_STACK_SIZE, stack_name, FAULT_ON_ERROR);
Packit bf408e
	*start = stack_addr - INT_STACK_SIZE;
Packit bf408e
	*end = stack_addr;
Packit bf408e
}
Packit bf408e
Packit bf408e
/*
Packit bf408e
 * Unroll a kernel stack.
Packit bf408e
 */
Packit bf408e
static void
Packit bf408e
s390_back_trace_cmd(struct bt_info *bt)
Packit bf408e
{
Packit bf408e
	char* stack;
Packit bf408e
	char async_stack[INT_STACK_SIZE];
Packit bf408e
	char panic_stack[INT_STACK_SIZE];
Packit bf408e
	long ksp,backchain,old_backchain;
Packit bf408e
	int i=0, r14_offset,bc_offset,r14, skip_first_frame=0;
Packit bf408e
	unsigned long async_start = 0, async_end = 0;
Packit bf408e
	unsigned long panic_start = 0, panic_end = 0;
Packit bf408e
	unsigned long stack_end, stack_start, stack_base;
Packit bf408e
	char buf[BUFSIZE];
Packit bf408e
	int cpu = bt->tc->processor;
Packit bf408e
Packit bf408e
	if (bt->hp && bt->hp->eip) {
Packit bf408e
		error(WARNING,
Packit bf408e
		"instruction pointer argument ignored on this architecture!\n");
Packit bf408e
	}
Packit bf408e
	if (is_task_active(bt->task) && !(kt->cpu_flags[cpu] & ONLINE_MAP)) {
Packit bf408e
		fprintf(fp, " CPU offline\n");
Packit bf408e
		return;
Packit bf408e
	}
Packit bf408e
	ksp = bt->stkptr;
Packit bf408e
Packit bf408e
	/* print lowcore and get async stack when task has cpu */
Packit bf408e
	if(s390_has_cpu(bt)){
Packit bf408e
		char lowcore[LOWCORE_SIZE];
Packit bf408e
		unsigned long psw_flags;
Packit bf408e
		int cpu = s390_cpu_of_task(bt->task);
Packit bf408e
Packit bf408e
		if (ACTIVE()) {
Packit bf408e
			fprintf(fp,"(active)\n");		
Packit bf408e
			return;
Packit bf408e
		}
Packit bf408e
		s390_get_lowcore(cpu,lowcore);
Packit bf408e
		psw_flags = ULONG(lowcore + OFFSET(s390_lowcore_psw_save_area));
Packit bf408e
		if(psw_flags & 0x10000UL){
Packit bf408e
				fprintf(fp,"Task runs in userspace\n");
Packit bf408e
				s390_print_lowcore(lowcore,bt,0);
Packit bf408e
				return;
Packit bf408e
		}
Packit bf408e
		s390_get_int_stack("async_stack", lowcore, async_stack,
Packit bf408e
				   &async_start, &async_end);
Packit bf408e
		s390_get_int_stack("panic_stack", lowcore, panic_stack,
Packit bf408e
				   &panic_start, &panic_end);
Packit bf408e
		s390_print_lowcore(lowcore,bt,1);
Packit bf408e
		fprintf(fp,"\n");
Packit bf408e
		skip_first_frame=1;
Packit bf408e
	}
Packit bf408e
Packit bf408e
	/* get task stack start and end */
Packit bf408e
	if(THIS_KERNEL_VERSION >= LINUX(2,6,0)){
Packit bf408e
		readmem(bt->task + OFFSET(task_struct_thread_info),KVADDR,
Packit bf408e
			&stack_start, sizeof(long), "thread info", 
Packit bf408e
			FAULT_ON_ERROR);
Packit bf408e
	} else {
Packit bf408e
		stack_start = bt->task;
Packit bf408e
	}
Packit bf408e
	stack_end   = stack_start + KERNEL_STACK_SIZE;
Packit bf408e
Packit bf408e
	if(!STRUCT_EXISTS("stack_frame")){
Packit bf408e
		r14_offset = 56;
Packit bf408e
		bc_offset=0;
Packit bf408e
	} else {
Packit bf408e
		r14_offset = MEMBER_OFFSET("stack_frame","gprs") + 
Packit bf408e
			     8 * S390_WORD_SIZE;
Packit bf408e
		bc_offset  = MEMBER_OFFSET("stack_frame","back_chain");
Packit bf408e
	}
Packit bf408e
	backchain = ksp;
Packit bf408e
	do {
Packit bf408e
		unsigned long r14_stack_off;
Packit bf408e
		struct load_module *lm;
Packit bf408e
		int j;
Packit bf408e
		ulong offset;
Packit bf408e
		char *name_plus_offset;
Packit bf408e
		struct syment *sp;
Packit bf408e
Packit bf408e
		/* Find stack: Either async, panic stack or task stack */
Packit bf408e
		if((backchain > stack_start) && (backchain < stack_end)){
Packit bf408e
			stack = bt->stackbuf;
Packit bf408e
			stack_base = stack_start;
Packit bf408e
		} else if((backchain > async_start) && (backchain < async_end)
Packit bf408e
			  && s390_has_cpu(bt)){
Packit bf408e
			stack = async_stack;
Packit bf408e
			stack_base = async_start;
Packit bf408e
		} else if((backchain > panic_start) && (backchain < panic_end)
Packit bf408e
			  && s390_has_cpu(bt)){
Packit bf408e
			stack = panic_stack;
Packit bf408e
			stack_base = panic_start;
Packit bf408e
		} else {
Packit bf408e
			/* invalid stackframe */
Packit bf408e
			break;
Packit bf408e
		}
Packit bf408e
		r14_stack_off=backchain - stack_base + r14_offset; 
Packit bf408e
		r14 = ULONG(&stack[r14_stack_off]) & S390_ADDR_MASK;
Packit bf408e
Packit bf408e
		/* print function name */
Packit bf408e
		if(BT_REFERENCE_CHECK(bt)){
Packit bf408e
			if(bt->ref->cmdflags & BT_REF_HEXVAL){
Packit bf408e
				if(r14 == bt->ref->hexval)
Packit bf408e
					bt->ref->cmdflags |= BT_REF_FOUND;
Packit bf408e
			} else {
Packit bf408e
				if(STREQ(closest_symbol(r14),bt->ref->str))
Packit bf408e
					bt->ref->cmdflags |= BT_REF_FOUND;
Packit bf408e
			}
Packit bf408e
		} else if(skip_first_frame){
Packit bf408e
			skip_first_frame=0;
Packit bf408e
		} else {
Packit bf408e
			fprintf(fp," #%i [%08lx] ",i,backchain);
Packit bf408e
			name_plus_offset = NULL;
Packit bf408e
			if (bt->flags & BT_SYMBOL_OFFSET) {
Packit bf408e
				sp = value_search(r14, &offset);
Packit bf408e
				if (sp && offset)
Packit bf408e
					name_plus_offset = 
Packit bf408e
						value_to_symstr(r14, buf, bt->radix);
Packit bf408e
			}
Packit bf408e
			fprintf(fp,"%s at %x", name_plus_offset ? 
Packit bf408e
				name_plus_offset : closest_symbol(r14), r14);
Packit bf408e
			if (module_symbol(r14, NULL, &lm, NULL, 0))
Packit bf408e
				fprintf(fp, " [%s]", lm->mod_name);
Packit bf408e
			fprintf(fp, "\n");
Packit bf408e
			if (bt->flags & BT_LINE_NUMBERS)
Packit bf408e
				s390_dump_line_number(r14);
Packit bf408e
			i++;
Packit bf408e
		}
Packit bf408e
		old_backchain=backchain;
Packit bf408e
		backchain = ULONG(&stack[backchain - stack_base + bc_offset]);
Packit bf408e
Packit bf408e
		/* print stack content if -f is specified */
Packit bf408e
		if((bt->flags & BT_FULL) && !BT_REFERENCE_CHECK(bt)){
Packit bf408e
			int frame_size;
Packit bf408e
			if(backchain == 0){
Packit bf408e
				frame_size = stack_base - old_backchain 
Packit bf408e
					     + KERNEL_STACK_SIZE;
Packit bf408e
			} else {
Packit bf408e
				frame_size = MIN((backchain - old_backchain),
Packit bf408e
					(stack_base - old_backchain +
Packit bf408e
					KERNEL_STACK_SIZE));
Packit bf408e
			}
Packit bf408e
			for(j=0; j< frame_size; j+=4){
Packit bf408e
				if(j % 16 == 0){
Packit bf408e
					fprintf(fp,"\n%08lx: ",old_backchain+j);
Packit bf408e
				}
Packit bf408e
				fprintf(fp," %s", format_stack_entry(bt, buf, 
Packit bf408e
					ULONG(&stack[old_backchain - stack_base + j]), 0));
Packit bf408e
			}
Packit bf408e
			fprintf(fp,"\n\n");
Packit bf408e
		}
Packit bf408e
Packit bf408e
		/* Check for interrupt stackframe */
Packit bf408e
		if((backchain == 0) && (stack == async_stack)){
Packit bf408e
			unsigned long psw_flags,r15;
Packit bf408e
Packit bf408e
			psw_flags = ULONG(&stack[old_backchain - stack_base 
Packit bf408e
					  +96 +MEMBER_OFFSET("pt_regs","psw")]);
Packit bf408e
			if(psw_flags & 0x10000UL){
Packit bf408e
				/* User psw: should not happen */
Packit bf408e
				break;
Packit bf408e
			}
Packit bf408e
			r15 = ULONG(&stack[old_backchain - stack_base +
Packit bf408e
				    96 + MEMBER_OFFSET("pt_regs",
Packit bf408e
				    "gprs") + 15 * S390_WORD_SIZE]);
Packit bf408e
			backchain=r15;
Packit bf408e
			fprintf(fp," - Interrupt -\n");
Packit bf408e
		}
Packit bf408e
      } while(backchain != 0);
Packit bf408e
}
Packit bf408e
Packit bf408e
/*
Packit bf408e
 * print lowcore info (psw and all registers)
Packit bf408e
 */
Packit bf408e
static void
Packit bf408e
s390_print_lowcore(char* lc, struct bt_info *bt, int show_symbols)
Packit bf408e
{
Packit bf408e
	char* ptr;
Packit bf408e
	unsigned long tmp[4];
Packit bf408e
Packit bf408e
	ptr = lc + OFFSET(s390_lowcore_psw_save_area);
Packit bf408e
	tmp[0]=ULONG(ptr);
Packit bf408e
	tmp[1]=ULONG(ptr + S390_WORD_SIZE);
Packit bf408e
Packit bf408e
	if(BT_REFERENCE_CHECK(bt)){
Packit bf408e
		if(bt->ref->cmdflags & BT_REF_HEXVAL){
Packit bf408e
			if(tmp[1] == bt->ref->hexval)
Packit bf408e
				bt->ref->cmdflags |= BT_REF_FOUND;
Packit bf408e
		} else {
Packit bf408e
			if(STREQ(closest_symbol(tmp[1]),bt->ref->str))
Packit bf408e
				bt->ref->cmdflags |= BT_REF_FOUND;
Packit bf408e
		}
Packit bf408e
		return;
Packit bf408e
	}
Packit bf408e
	fprintf(fp," LOWCORE INFO:\n");
Packit bf408e
	fprintf(fp,"  -psw      : %#010lx %#010lx\n", tmp[0],
Packit bf408e
		tmp[1]);
Packit bf408e
	if(show_symbols){
Packit bf408e
		fprintf(fp,"  -function : %s at %lx\n", 
Packit bf408e
	       		closest_symbol(tmp[1] & S390_ADDR_MASK), 
Packit bf408e
			tmp[1] & S390_ADDR_MASK);
Packit bf408e
		if (bt->flags & BT_LINE_NUMBERS)
Packit bf408e
	       		s390_dump_line_number(tmp[1] & S390_ADDR_MASK);
Packit bf408e
	}	
Packit bf408e
	ptr = lc + MEMBER_OFFSET(lc_struct, "cpu_timer_save_area");
Packit bf408e
	tmp[0]=UINT(ptr);
Packit bf408e
	tmp[1]=UINT(ptr + S390_WORD_SIZE);
Packit bf408e
	fprintf(fp,"  -cpu timer: %#010lx %#010lx\n", tmp[0],tmp[1]);
Packit bf408e
Packit bf408e
	ptr = lc + MEMBER_OFFSET(lc_struct, "clock_comp_save_area");
Packit bf408e
	tmp[0]=UINT(ptr);
Packit bf408e
	tmp[1]=UINT(ptr + S390_WORD_SIZE);
Packit bf408e
	fprintf(fp,"  -clock cmp: %#010lx %#010lx\n", tmp[0], tmp[1]);
Packit bf408e
Packit bf408e
	fprintf(fp,"  -general registers:\n");
Packit bf408e
	ptr = lc + MEMBER_OFFSET(lc_struct, "gpregs_save_area");
Packit bf408e
	tmp[0]=ULONG(ptr);
Packit bf408e
	tmp[1]=ULONG(ptr + S390_WORD_SIZE);
Packit bf408e
	tmp[2]=ULONG(ptr + 2 * S390_WORD_SIZE);
Packit bf408e
	tmp[3]=ULONG(ptr + 3 * S390_WORD_SIZE);
Packit bf408e
	fprintf(fp,"     %#010lx %#010lx %#010lx %#010lx\n", 
Packit bf408e
		tmp[0],tmp[1],tmp[2],tmp[3]);
Packit bf408e
	tmp[0]=ULONG(ptr + 4 * S390_WORD_SIZE);
Packit bf408e
	tmp[1]=ULONG(ptr + 5 * S390_WORD_SIZE);
Packit bf408e
	tmp[2]=ULONG(ptr + 6 * S390_WORD_SIZE);
Packit bf408e
	tmp[3]=ULONG(ptr + 7 * S390_WORD_SIZE);
Packit bf408e
	fprintf(fp,"     %#010lx %#010lx %#010lx %#010lx\n", 
Packit bf408e
		tmp[0],tmp[1],tmp[2],tmp[3]);
Packit bf408e
	tmp[0]=ULONG(ptr + 8 * S390_WORD_SIZE);
Packit bf408e
	tmp[1]=ULONG(ptr + 9 * S390_WORD_SIZE);
Packit bf408e
	tmp[2]=ULONG(ptr + 10* S390_WORD_SIZE);
Packit bf408e
	tmp[3]=ULONG(ptr + 11* S390_WORD_SIZE);
Packit bf408e
	fprintf(fp,"     %#010lx %#010lx %#010lx %#010lx\n", 
Packit bf408e
		tmp[0],tmp[1],tmp[2],tmp[3]);
Packit bf408e
	tmp[0]=ULONG(ptr + 12* S390_WORD_SIZE);
Packit bf408e
	tmp[1]=ULONG(ptr + 13* S390_WORD_SIZE);
Packit bf408e
	tmp[2]=ULONG(ptr + 14* S390_WORD_SIZE);
Packit bf408e
	tmp[3]=ULONG(ptr + 15* S390_WORD_SIZE);
Packit bf408e
	fprintf(fp,"     %#010lx %#010lx %#010lx %#010lx\n", 
Packit bf408e
		tmp[0], tmp[1], tmp[2], tmp[3]);
Packit bf408e
Packit bf408e
	fprintf(fp,"  -access registers:\n");
Packit bf408e
	ptr = lc + MEMBER_OFFSET(lc_struct, "access_regs_save_area");
Packit bf408e
	tmp[0]=ULONG(ptr);
Packit bf408e
	tmp[1]=ULONG(ptr + S390_WORD_SIZE);
Packit bf408e
	tmp[2]=ULONG(ptr + 2 * S390_WORD_SIZE);
Packit bf408e
	tmp[3]=ULONG(ptr + 3 * S390_WORD_SIZE);
Packit bf408e
	fprintf(fp,"     %#010lx %#010lx %#010lx %#010lx\n", 
Packit bf408e
		tmp[0], tmp[1], tmp[2], tmp[3]);
Packit bf408e
	tmp[0]=ULONG(ptr + 4 * S390_WORD_SIZE);
Packit bf408e
	tmp[1]=ULONG(ptr + 5 * S390_WORD_SIZE);
Packit bf408e
	tmp[2]=ULONG(ptr + 6 * S390_WORD_SIZE);
Packit bf408e
	tmp[3]=ULONG(ptr + 7 * S390_WORD_SIZE);
Packit bf408e
	fprintf(fp,"     %#010lx %#010lx %#010lx %#010lx\n", 
Packit bf408e
		tmp[0], tmp[1], tmp[2], tmp[3]);
Packit bf408e
	tmp[0]=ULONG(ptr + 8 * S390_WORD_SIZE);
Packit bf408e
	tmp[1]=ULONG(ptr + 9 * S390_WORD_SIZE);
Packit bf408e
	tmp[2]=ULONG(ptr + 10* S390_WORD_SIZE);
Packit bf408e
	tmp[3]=ULONG(ptr + 11* S390_WORD_SIZE);
Packit bf408e
	fprintf(fp,"     %#010lx %#010lx %#010lx %#010lx\n", 
Packit bf408e
		tmp[0], tmp[1], tmp[2], tmp[3]);
Packit bf408e
	tmp[0]=ULONG(ptr + 12* S390_WORD_SIZE);
Packit bf408e
	tmp[1]=ULONG(ptr + 13* S390_WORD_SIZE);
Packit bf408e
	tmp[2]=ULONG(ptr + 14* S390_WORD_SIZE);
Packit bf408e
	tmp[3]=ULONG(ptr + 15* S390_WORD_SIZE);
Packit bf408e
	fprintf(fp,"     %#010lx %#010lx %#010lx %#010lx\n", 
Packit bf408e
		tmp[0], tmp[1], tmp[2], tmp[3]);
Packit bf408e
Packit bf408e
	fprintf(fp,"  -control registers:\n");
Packit bf408e
	ptr = lc + MEMBER_OFFSET(lc_struct, "cregs_save_area");
Packit bf408e
	tmp[0]=ULONG(ptr);
Packit bf408e
	tmp[1]=ULONG(ptr + S390_WORD_SIZE);
Packit bf408e
	tmp[2]=ULONG(ptr + 2 * S390_WORD_SIZE);
Packit bf408e
	tmp[3]=ULONG(ptr + 3 * S390_WORD_SIZE);
Packit bf408e
	fprintf(fp,"     %#010lx %#010lx %#010lx %#010lx\n", 
Packit bf408e
		tmp[0], tmp[1], tmp[2], tmp[3]);
Packit bf408e
	tmp[0]=ULONG(ptr + 4 * S390_WORD_SIZE);
Packit bf408e
	tmp[1]=ULONG(ptr + 5 * S390_WORD_SIZE);
Packit bf408e
	tmp[2]=ULONG(ptr + 6 * S390_WORD_SIZE);
Packit bf408e
	tmp[3]=ULONG(ptr + 7 * S390_WORD_SIZE);
Packit bf408e
	fprintf(fp,"     %#010lx %#010lx %#010lx %#010lx\n", 
Packit bf408e
		tmp[0], tmp[1], tmp[2], tmp[3]);
Packit bf408e
Packit bf408e
	tmp[0]=ULONG(ptr + 8 * S390_WORD_SIZE);
Packit bf408e
	tmp[1]=ULONG(ptr + 9 * S390_WORD_SIZE);
Packit bf408e
	tmp[2]=ULONG(ptr + 10 * S390_WORD_SIZE);
Packit bf408e
	tmp[3]=ULONG(ptr + 11 * S390_WORD_SIZE);
Packit bf408e
	fprintf(fp,"     %#010lx %#010lx %#010lx %#010lx\n", 
Packit bf408e
		tmp[0], tmp[1], tmp[2], tmp[3]);
Packit bf408e
	tmp[0]=ULONG(ptr + 12 * S390_WORD_SIZE);
Packit bf408e
	tmp[1]=ULONG(ptr + 13 * S390_WORD_SIZE);
Packit bf408e
	tmp[2]=ULONG(ptr + 14 * S390_WORD_SIZE);
Packit bf408e
	tmp[3]=ULONG(ptr + 15 * S390_WORD_SIZE);
Packit bf408e
	fprintf(fp,"     %#010lx %#010lx %#010lx %#010lx\n", 
Packit bf408e
		tmp[0], tmp[1], tmp[2], tmp[3]);
Packit bf408e
Packit bf408e
	ptr = lc + MEMBER_OFFSET(lc_struct, "floating_pt_save_area");
Packit bf408e
	fprintf(fp,"  -floating point registers 0,2,4,6:\n");
Packit bf408e
	tmp[0]=ULONG(ptr);
Packit bf408e
	tmp[1]=ULONG(ptr + 2 * S390_WORD_SIZE);
Packit bf408e
	tmp[2]=ULONG(ptr + 4 * S390_WORD_SIZE);
Packit bf408e
	tmp[3]=ULONG(ptr + 6 * S390_WORD_SIZE);
Packit bf408e
	fprintf(fp,"     %#018lx %#018lx\n", tmp[0], tmp[1]);
Packit bf408e
	fprintf(fp,"     %#018lx %#018lx\n", tmp[2], tmp[3]);
Packit bf408e
}
Packit bf408e
Packit bf408e
/*
Packit bf408e
 *  Get a stack frame combination of pc and ra from the most relevent spot.
Packit bf408e
 */
Packit bf408e
static void
Packit bf408e
s390_get_stack_frame(struct bt_info *bt, ulong *eip, ulong *esp)
Packit bf408e
{
Packit bf408e
	unsigned long ksp, r14;
Packit bf408e
	int r14_offset;
Packit bf408e
	char lowcore[LOWCORE_SIZE];
Packit bf408e
Packit bf408e
	if(s390_has_cpu(bt))
Packit bf408e
		s390_get_lowcore(s390_cpu_of_task(bt->task),lowcore);
Packit bf408e
Packit bf408e
	/* get the stack pointer */
Packit bf408e
	if(esp){
Packit bf408e
		if(s390_has_cpu(bt)){
Packit bf408e
			ksp = ULONG(lowcore + MEMBER_OFFSET(lc_struct,
Packit bf408e
				"gpregs_save_area") + (15 * S390_WORD_SIZE));
Packit bf408e
		} else {
Packit bf408e
			readmem(bt->task + OFFSET(task_struct_thread_ksp),
Packit bf408e
				KVADDR, &ksp, sizeof(void *),
Packit bf408e
				"thread_struct ksp", FAULT_ON_ERROR);
Packit bf408e
		}
Packit bf408e
		*esp = ksp;
Packit bf408e
	} else {
Packit bf408e
		/* for 'bt -S' */
Packit bf408e
		ksp=bt->hp->esp;
Packit bf408e
	}
Packit bf408e
Packit bf408e
	/* get the instruction address */
Packit bf408e
	if(!eip)
Packit bf408e
		return;
Packit bf408e
Packit bf408e
	if(s390_has_cpu(bt) && esp){
Packit bf408e
		*eip = ULONG(lowcore + OFFSET(s390_lowcore_psw_save_area) +
Packit bf408e
			S390_WORD_SIZE) & S390_ADDR_MASK;
Packit bf408e
	} else {
Packit bf408e
		if(!STRUCT_EXISTS("stack_frame")){
Packit bf408e
			r14_offset = 56;
Packit bf408e
		} else {
Packit bf408e
			r14_offset = MEMBER_OFFSET("stack_frame","gprs") +
Packit bf408e
				     8 * S390_WORD_SIZE;
Packit bf408e
		}
Packit bf408e
		readmem(ksp + r14_offset,KVADDR,&r14,sizeof(void*),"eip",
Packit bf408e
	       		FAULT_ON_ERROR);
Packit bf408e
		*eip=r14 & S390_ADDR_MASK;
Packit bf408e
	}
Packit bf408e
}
Packit bf408e
Packit bf408e
/*
Packit bf408e
 *  Filter disassembly output if the output radix is not gdb's default 10
Packit bf408e
 */
Packit bf408e
static int 
Packit bf408e
s390_dis_filter(ulong vaddr, char *inbuf, unsigned int output_radix)
Packit bf408e
{
Packit bf408e
	char buf1[BUFSIZE];
Packit bf408e
	char buf2[BUFSIZE];
Packit bf408e
	char *colon, *p1;
Packit bf408e
	int argc;
Packit bf408e
	char *argv[MAXARGS];
Packit bf408e
	ulong value;
Packit bf408e
Packit bf408e
	if (!inbuf) 
Packit bf408e
		return TRUE;
Packit bf408e
/*
Packit bf408e
 *  For some reason gdb can go off into the weeds translating text addresses,
Packit bf408e
 *  so this routine both fixes the references as well as imposing the current 
Packit bf408e
 *  output radix on the translations.
Packit bf408e
 */
Packit bf408e
	console("IN: %s", inbuf);
Packit bf408e
Packit bf408e
	colon = strstr(inbuf, ":");
Packit bf408e
Packit bf408e
	if (colon) {
Packit bf408e
		sprintf(buf1, "0x%lx <%s>", vaddr,
Packit bf408e
			value_to_symstr(vaddr, buf2, output_radix));
Packit bf408e
		sprintf(buf2, "%s%s", buf1, colon);
Packit bf408e
		strcpy(inbuf, buf2);
Packit bf408e
	}
Packit bf408e
Packit bf408e
	strcpy(buf1, inbuf);
Packit bf408e
	argc = parse_line(buf1, argv);
Packit bf408e
Packit bf408e
	if ((FIRSTCHAR(argv[argc-1]) == '<') && 
Packit bf408e
	    (LASTCHAR(argv[argc-1]) == '>')) {
Packit bf408e
		p1 = rindex(inbuf, '<');
Packit bf408e
		while ((p1 > inbuf) && !STRNEQ(p1, " 0x")) 
Packit bf408e
			p1--;
Packit bf408e
Packit bf408e
		if (!STRNEQ(p1, " 0x"))
Packit bf408e
			return FALSE;
Packit bf408e
		p1++;
Packit bf408e
Packit bf408e
		if (!extract_hex(p1, &value, NULLCHAR, TRUE))
Packit bf408e
			return FALSE;
Packit bf408e
Packit bf408e
		sprintf(buf1, "0x%lx <%s>\n", value,
Packit bf408e
			value_to_symstr(value, buf2, output_radix));
Packit bf408e
Packit bf408e
		sprintf(p1, "%s", buf1);
Packit bf408e
	}
Packit bf408e
Packit bf408e
	console("    %s", inbuf);
Packit bf408e
Packit bf408e
	return TRUE;
Packit bf408e
}
Packit bf408e
Packit bf408e
/*
Packit bf408e
 *   Override smp_num_cpus if possible and necessary.
Packit bf408e
 */
Packit bf408e
int
Packit bf408e
s390_get_smp_cpus(void)
Packit bf408e
{
Packit bf408e
	return MAX(get_cpus_online(), get_highest_cpu_online()+1);
Packit bf408e
}
Packit bf408e
Packit bf408e
/*
Packit bf408e
 *  Machine dependent command.
Packit bf408e
 */
Packit bf408e
void
Packit bf408e
s390_cmd_mach(void)
Packit bf408e
{
Packit bf408e
	int c;
Packit bf408e
Packit bf408e
	while ((c = getopt(argcnt, args, "cm")) != EOF) {
Packit bf408e
		switch(c)
Packit bf408e
		{
Packit bf408e
		case 'c':
Packit bf408e
			fprintf(fp,"'-c' option is not implemented on this architecture\n");
Packit bf408e
			return;
Packit bf408e
		case 'm':
Packit bf408e
			fprintf(fp,"'-m' option is not implemented on this architecture\n");
Packit bf408e
			return;
Packit bf408e
		default:
Packit bf408e
			argerrs++;
Packit bf408e
			break;
Packit bf408e
		}
Packit bf408e
	}
Packit bf408e
Packit bf408e
	if (argerrs)
Packit bf408e
		cmd_usage(pc->curcmd, SYNOPSIS);
Packit bf408e
Packit bf408e
	s390_display_machine_stats();
Packit bf408e
}
Packit bf408e
Packit bf408e
/*
Packit bf408e
 *  "mach" command output.
Packit bf408e
 */
Packit bf408e
static void
Packit bf408e
s390_display_machine_stats(void)
Packit bf408e
{
Packit bf408e
	struct new_utsname *uts;
Packit bf408e
	char buf[BUFSIZE];
Packit bf408e
	ulong mhz;
Packit bf408e
Packit bf408e
	uts = &kt->utsname;
Packit bf408e
Packit bf408e
	fprintf(fp, "       MACHINE TYPE: %s\n", uts->machine);
Packit bf408e
	fprintf(fp, "        MEMORY SIZE: %s\n", get_memory_size(buf));
Packit bf408e
	fprintf(fp, "               CPUS: %d\n", kt->cpus);
Packit bf408e
	fprintf(fp, "    PROCESSOR SPEED: ");
Packit bf408e
	if ((mhz = machdep->processor_speed()))
Packit bf408e
		fprintf(fp, "%ld Mhz\n", mhz);
Packit bf408e
	else
Packit bf408e
		fprintf(fp, "(unknown)\n");
Packit bf408e
	fprintf(fp, "                 HZ: %d\n", machdep->hz);
Packit bf408e
	fprintf(fp, "          PAGE SIZE: %d\n", PAGESIZE());
Packit bf408e
	// fprintf(fp, "      L1 CACHE SIZE: %d\n", l1_cache_size());
Packit bf408e
	fprintf(fp, "KERNEL VIRTUAL BASE: %lx\n", machdep->kvbase);
Packit bf408e
	fprintf(fp, "KERNEL VMALLOC BASE: %lx\n", vt->vmalloc_start);
Packit bf408e
	fprintf(fp, "  KERNEL STACK SIZE: %ld\n", STACKSIZE());
Packit bf408e
Packit bf408e
}
Packit bf408e
Packit bf408e
static const char *hook_files[] = {
Packit bf408e
	"arch/s390/kernel/entry.S",
Packit bf408e
	"arch/s390/kernel/head.S"
Packit bf408e
};
Packit bf408e
Packit bf408e
#define ENTRY_S      ((char **)&hook_files[0])
Packit bf408e
#define HEAD_S       ((char **)&hook_files[1])
Packit bf408e
Packit bf408e
static struct line_number_hook s390_line_number_hooks[] = {
Packit bf408e
       {"startup",HEAD_S},
Packit bf408e
       {"_stext",HEAD_S},
Packit bf408e
       {"_pstart",HEAD_S},
Packit bf408e
       {"system_call",ENTRY_S},
Packit bf408e
       {"sysc_do_svc",ENTRY_S},
Packit bf408e
       {"sysc_do_restart",ENTRY_S},
Packit bf408e
       {"sysc_return",ENTRY_S},
Packit bf408e
       {"sysc_sigpending",ENTRY_S},
Packit bf408e
       {"sysc_restart",ENTRY_S},
Packit bf408e
       {"sysc_singlestep",ENTRY_S},
Packit bf408e
       {"sysc_tracesys",ENTRY_S},
Packit bf408e
       {"ret_from_fork",ENTRY_S},
Packit bf408e
       {"pgm_check_handler",ENTRY_S},
Packit bf408e
       {"io_int_handler",ENTRY_S},
Packit bf408e
       {"io_return",ENTRY_S},
Packit bf408e
       {"ext_int_handler",ENTRY_S},
Packit bf408e
       {"mcck_int_handler",ENTRY_S},
Packit bf408e
       {"mcck_return",ENTRY_S},
Packit bf408e
       {"restart_int_handler",ENTRY_S},
Packit bf408e
       {NULL, NULL}    /* list must be NULL-terminated */
Packit bf408e
};
Packit bf408e
Packit bf408e
static void
Packit bf408e
s390_dump_line_number(ulong callpc)
Packit bf408e
{
Packit bf408e
	int retries;
Packit bf408e
	char buf[BUFSIZE], *p;
Packit bf408e
Packit bf408e
	retries = 0;
Packit bf408e
try_closest:
Packit bf408e
	get_line_number(callpc, buf, FALSE);
Packit bf408e
Packit bf408e
	if (strlen(buf)) {
Packit bf408e
		if (retries) {
Packit bf408e
			p = strstr(buf, ": ");
Packit bf408e
			if (p)
Packit bf408e
				*p = NULLCHAR;
Packit bf408e
		}
Packit bf408e
		fprintf(fp, "    %s\n", buf);
Packit bf408e
	} else {
Packit bf408e
		if (retries) {
Packit bf408e
			fprintf(fp, GDB_PATCHED() ?
Packit bf408e
			  "" : "    (cannot determine file and line number)\n");
Packit bf408e
		} else {
Packit bf408e
			retries++;
Packit bf408e
			callpc = closest_symbol_value(callpc);
Packit bf408e
			goto try_closest;
Packit bf408e
		}
Packit bf408e
	}
Packit bf408e
}
Packit bf408e
Packit bf408e
#endif