This is an updated version of Cell/B.E. SPU commands extension.
debug_spu_info was renamed to crash_spu_info in the kernel code.

Signed-off-by Lucio Correia <[EMAIL PROTECTED]>


diff -Nurp crash-4.0-4.3.orig/extensions/Makefile 
crash-4.0-4.3/extensions/Makefile
--- crash-4.0-4.3.orig/extensions/Makefile      2007-06-22 15:49:16.000000000 
-0300
+++ crash-4.0-4.3/extensions/Makefile   2007-06-28 13:37:27.000000000 -0300
@@ -41,3 +41,6 @@ dminfo.so: ../defs.h dminfo.c
        gcc -nostartfiles -shared -rdynamic -o dminfo.so dminfo.c -fPIC \
                                                -D$(TARGET) $(TARGET_CFLAGS)
        
+spu.so: ../defs.h spu.c
+       gcc -nostartfiles -shared -rdynamic -o spu.so spu.c -fPIC \
+                                               -D$(TARGET) $(TARGET_CFLAGS)
diff -Nurp crash-4.0-4.3.orig/extensions/spu.c crash-4.0-4.3/extensions/spu.c
--- crash-4.0-4.3.orig/extensions/spu.c 1969-12-31 21:00:00.000000000 -0300
+++ crash-4.0-4.3/extensions/spu.c      2007-06-29 17:18:32.000000000 -0300
@@ -0,0 +1,1011 @@
+/* spu.c - commands for viewing Cell/B.E. SPUs data
+ *
+ * (C) Copyright 2007 IBM Corp.
+ *
+ * Author: Lucio Correia <[EMAIL PROTECTED]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "defs.h"
+
+#define NR_SPUS                         (16)   /* Enough for current hardware 
*/
+#define MAX_PRIO               (140)
+#define MAX_PROPERTY_NAME       (64)
+#define STR_SPU_INVALID                (0x0)
+#define STR_SPU_ID             (0x1)
+#define STR_SPU_PID            (0x2)
+#define STR_SPU_CTX_ADDR       (0x8)
+
+#define SPUCTX_CMD_NAME "spuctx"
+#define SPUS_CMD_NAME "spus"
+#define SPURQ_CMD_NAME "spurq"
+
+struct cbe_size_table;
+struct cbe_offset_table;
+void init_cbe_size_table(void);
+void init_cbe_offset_table(void);
+ulong get_spu_addr(ulong spu_info);
+
+void cmd_spus(void);
+void cmd_spurq(void);
+void cmd_spuctx(void);
+char *help_spus[];
+char *help_spurq[];
+void show_spu_state(ulong spu);
+void dump_spu_runq(ulong k_prio_array);
+char *help_spuctx[];
+void show_ctx_info(ulong ctx_addr);
+void print_ctx_info(char *ctx_data, char *spu_data, int info);
+void show_ctx_info_all(void);
+
+
+static struct command_table_entry command_table[] = {
+       SPUCTX_CMD_NAME, cmd_spuctx, help_spuctx, 0,
+       SPUS_CMD_NAME, cmd_spus, help_spus, 0,
+       SPURQ_CMD_NAME, cmd_spurq, help_spurq, 0,
+       NULL
+};
+
+struct cbe_size_table {
+       long crash_spu_info;
+       long spu;
+       long spu_context;
+       long spu_prio_array;
+       long list_head;
+} cbe_size_table;
+
+struct cbe_offset_table {
+       long crash_spu_info_spu;
+       long crash_spu_info_saved_mfc_sr1_RW;
+       long crash_spu_info_saved_mfc_dar;
+       long crash_spu_info_saved_mfc_dsisr;
+       long crash_spu_info_saved_spu_runcntl_RW;
+       long crash_spu_info_saved_spu_status_R;
+       long crash_spu_info_saved_spu_npc_RW;
+
+       long spu_node;
+       long spu_number;
+       long spu_ctx;
+       long spu_pid;
+       long spu_name;
+       long spu_slb_replace;
+       long spu_mm;
+       long spu_timestamp;
+       long spu_class_0_pending;
+       long spu_problem;
+       long spu_priv2;
+       long spu_flags;
+
+       long spu_context_spu;
+       long spu_context_state;
+       long spu_context_prio;
+       long spu_context_local_store;
+       long spu_context_rq;
+
+       long spu_prio_array_runq;
+} cbe_offset_table;
+
+#define CBE_SIZE(X)                    (cbe_size_table.X)
+#define CBE_OFFSET(X, Y)               (cbe_offset_table.X##_##Y)
+
+#define CBE_SIZE_INIT(X, Y)                                            \
+do {                                                                   \
+       cbe_size_table.X = STRUCT_SIZE(Y);                              \
+       if (cbe_size_table.X == -1)                                     \
+               error(FATAL, "Couldn't get %s size.\n", Y);             \
+} while(0)
+
+#define CBE_OFFSET_INIT(X, Y, Z)                                       \
+do {                                                                   \
+       cbe_offset_table.X = MEMBER_OFFSET(Y, Z);                       \
+       if (cbe_offset_table.X == -1)                                   \
+               error(FATAL, "Couldn't get %s.%s offset.\n", Y, Z);     \
+} while(0)
+
+ulong spu[NR_SPUS];
+
+/*****************************************************************************
+ * INIT FUNCTIONS
+ */
+
+/*
+ * Read kernel virtual addresses of crash_spu_info data stored by kdump
+ */
+
+void init_cbe_size_table(void)
+{
+       CBE_SIZE_INIT(crash_spu_info, "crash_spu_info");
+       CBE_SIZE_INIT(spu, "spu");
+       CBE_SIZE_INIT(spu_context, "spu_context");
+       CBE_SIZE_INIT(spu_prio_array, "spu_prio_array");
+       CBE_SIZE_INIT(list_head, "list_head");
+}
+
+void init_cbe_offset_table(void)
+{
+       CBE_OFFSET_INIT(crash_spu_info_spu, "crash_spu_info", "spu");
+       CBE_OFFSET_INIT(crash_spu_info_saved_mfc_sr1_RW, "crash_spu_info",
+                                                       "saved_mfc_sr1_RW");
+       CBE_OFFSET_INIT(crash_spu_info_saved_mfc_dar, "crash_spu_info",
+                                                       "saved_mfc_dar");
+       CBE_OFFSET_INIT(crash_spu_info_saved_mfc_dsisr, "crash_spu_info",
+                                                       "saved_mfc_dsisr");
+       CBE_OFFSET_INIT(crash_spu_info_saved_spu_runcntl_RW, "crash_spu_info",
+                                                       "saved_spu_runcntl_RW");
+       CBE_OFFSET_INIT(crash_spu_info_saved_spu_status_R, "crash_spu_info",
+                                                       "saved_spu_status_R");
+       CBE_OFFSET_INIT(crash_spu_info_saved_spu_npc_RW, "crash_spu_info",
+                                                       "saved_spu_npc_RW");
+
+       CBE_OFFSET_INIT(spu_node, "spu", "node");
+       CBE_OFFSET_INIT(spu_number, "spu", "number");
+       CBE_OFFSET_INIT(spu_ctx, "spu", "ctx");
+       CBE_OFFSET_INIT(spu_pid, "spu", "pid");
+       CBE_OFFSET_INIT(spu_name, "spu", "name");
+       CBE_OFFSET_INIT(spu_slb_replace, "spu", "slb_replace");
+       CBE_OFFSET_INIT(spu_mm, "spu", "mm");
+       CBE_OFFSET_INIT(spu_timestamp, "spu", "timestamp");
+       CBE_OFFSET_INIT(spu_class_0_pending, "spu", "class_0_pending");
+       CBE_OFFSET_INIT(spu_problem, "spu", "problem");
+       CBE_OFFSET_INIT(spu_priv2, "spu", "priv2");
+       CBE_OFFSET_INIT(spu_flags, "spu", "flags");
+
+       CBE_OFFSET_INIT(spu_context_spu, "spu_context", "spu");
+       CBE_OFFSET_INIT(spu_context_state, "spu_context", "state");
+       CBE_OFFSET_INIT(spu_context_prio, "spu_context", "prio");
+       CBE_OFFSET_INIT(spu_context_local_store, "spu_context", "local_store");
+       CBE_OFFSET_INIT(spu_context_rq, "spu_context", "rq");
+
+       CBE_OFFSET_INIT(spu_prio_array_runq, "spu_prio_array", "runq");
+}
+
+void get_crash_spu_info(void)
+{
+       int i;
+       ulong addr;
+       long struct_size;
+
+       addr = symbol_value("crash_spu_info");
+       struct_size = CBE_SIZE(crash_spu_info);
+
+       for (i = 0; i < NR_SPUS; i++)
+               spu[i] = addr + (i * struct_size);
+}
+
+_init()
+{
+       int i, n_registered;
+       struct command_table_entry *cte;
+
+       init_cbe_size_table();
+       init_cbe_offset_table();
+
+       for (i = 0; i < NR_SPUS; i++)
+               spu[i] = 0;
+
+       register_extension(command_table);
+
+       get_crash_spu_info();
+}
+
+
+_fini() { }
+
+
+
+/*****************************************************************************
+ * BASIC FUNCTIONS
+ */
+
+
+/*
+ * Returns a pointer to the requested SPU field 
+ */
+ulong get_spu_addr(ulong spu_info)
+{
+       ulong spu_addr;
+
+       readmem(spu_info + CBE_OFFSET(crash_spu_info, spu), KVADDR, &spu_addr, 
+                       sizeof(spu_addr), "get_spu_addr", FAULT_ON_ERROR);
+
+       return spu_addr;
+}
+
+
+/*****************************************************************************
+ * SPUCTX COMMAND
+ */
+
+#define DUMP_WIDTH     23
+#define DUMP_SPU_NAME                                                  \
+do {                                                                   \
+       fprintf(fp, "  %-*s = %s\n", DUMP_WIDTH, "name", name_str);     \
+} while(0)
+
+#define DUMP_SPU_FIELD(format, field, cast)                            \
+do {                                                                   \
+       offset = CBE_OFFSET(spu, field);                                \
+       fprintf(fp, "  %-*s = "format"\n", DUMP_WIDTH, #field,          \
+                                       cast(spu_data + offset));       \
+} while(0)
+
+#define DUMP_CTX_FIELD(format, field, cast)                            \
+do {                                                                   \
+       offset = CBE_OFFSET(spu_context, field);                        \
+       fprintf(fp, "  %-*s = "format"\n", DUMP_WIDTH, #field,          \
+                                       cast(ctx_data + offset));       \
+} while(0)
+
+#define DUMP_DBG_FIELD(format, field, cast)                            \
+do {                                                                   \
+       offset = CBE_OFFSET(crash_spu_info, field);                     \
+       fprintf(fp, "  %-*s = "format"\n", DUMP_WIDTH, #field,          \
+                                       cast(debug_data + offset));     \
+} while(0)
+
+/* 
+ * Print the spu and spu_context structs fields. Some SPU memory-mapped IO 
+ * registers are taken directly from crash_spu_info.
+ */
+void print_ctx_info(char *ctx_data, char *spu_data, int info)
+{
+       long offset, size;
+       char *name_str, *debug_data;
+
+       DUMP_CTX_FIELD("%d", state, *(int *));
+       DUMP_CTX_FIELD("%d", prio, *(int *));
+       DUMP_CTX_FIELD("%p", local_store, *(ulong *));
+       DUMP_CTX_FIELD("%p", rq, *(ulong *));
+
+       if (spu_data) {
+               offset = CBE_OFFSET(spu, name);
+               size = MAX_PROPERTY_NAME * sizeof(char);
+               name_str = (char *)GETBUF(size);
+               readmem(*(ulong *)(spu_data + offset), KVADDR, name_str, size,
+                                               "name_str", FAULT_ON_ERROR);
+               DUMP_SPU_NAME;
+               FREEBUF(name_str);
+
+               DUMP_SPU_FIELD("%d", node, *(int *));
+               DUMP_SPU_FIELD("%d", number, *(int *));
+               DUMP_SPU_FIELD("%d", pid, *(int *));
+               DUMP_SPU_FIELD("0x%x", slb_replace, *(unsigned int *));
+               DUMP_SPU_FIELD("%p", mm, *(ulong *));
+               DUMP_SPU_FIELD("%p", timestamp, *(long long *));
+               DUMP_SPU_FIELD("%d", class_0_pending, *(int *));
+               DUMP_SPU_FIELD("%p", problem, *(ulong *));
+               DUMP_SPU_FIELD("%p", priv2, *(ulong *));
+               DUMP_SPU_FIELD("0x%lx", flags, *(ulong *));
+
+               size = CBE_SIZE(crash_spu_info);
+               debug_data = (char *)GETBUF(size);
+               readmem(spu[info], KVADDR, debug_data, size, "debug_data",
+                                                               FAULT_ON_ERROR);
+
+               DUMP_DBG_FIELD("0x%lx", saved_mfc_sr1_RW, *(ulong *));
+               DUMP_DBG_FIELD("0x%lx", saved_mfc_dar, *(ulong *));
+               DUMP_DBG_FIELD("0x%lx", saved_mfc_dsisr, *(ulong *));
+               DUMP_DBG_FIELD("0x%x", saved_spu_runcntl_RW, *(uint *));
+               DUMP_DBG_FIELD("0x%x", saved_spu_status_R, *(uint *));
+               DUMP_DBG_FIELD("0x%x", saved_spu_npc_RW, *(uint *));
+
+               FREEBUF(debug_data);
+       }
+}
+
+
+/*
+ * Pass ctx and respective spu data to print_ctx_info for the contexts in
+ * ctx_addr list (chosen contexts).
+ */
+void show_ctx_info(ulong ctx_addr)
+{
+       int number, info, i;
+       char *ctx_data, *spu_data;
+       long size, offset;
+       ulong spu_addr, addr;
+
+       spu_data = NULL;
+       info = 0;
+
+       size = CBE_SIZE(spu_context);
+       ctx_data = GETBUF(size);
+       if (!ctx_data)
+               error(FATAL, "Couldn't allocate memory for ctx.\n");
+       readmem(ctx_addr, KVADDR, ctx_data, size, "show_ctx_info ctx", 
+                                                               FAULT_ON_ERROR);
+
+       spu_addr = *(ulong *)(ctx_data + CBE_OFFSET(spu_context, spu));
+
+       if (spu_addr) {
+               size = CBE_SIZE(spu);
+               spu_data = GETBUF(size);
+               if (!spu_data)
+                       error(FATAL, "Couldn't allocate memory for spu.\n");
+               readmem(spu_addr, KVADDR, spu_data, size, "show_ctx_info spu",
+                                                               FAULT_ON_ERROR);
+
+               for (i = 0; i < NR_SPUS; i++) {
+                       readmem(spu[i], KVADDR, &addr, sizeof(addr), "spu addr",
+                                                               FAULT_ON_ERROR);
+                       if (addr == spu_addr)
+                               info = i;
+               }
+       }
+
+       fprintf(fp,"\nDumping context fields for spu_context %lx:\n", ctx_addr);
+       print_ctx_info(ctx_data, spu_data, info);
+
+       FREEBUF(ctx_data);
+       if (spu_addr)
+               FREEBUF(spu_data);
+}
+
+/*
+ * Pass ctx and respective spu data to show_ctx_info for all the contexts
+ * running and on the runqueue.
+ */
+void show_ctx_info_all(void)
+{
+       int i, j, cnt;
+       long prio_size, prio_runq_off, ctx_rq_off, jump, offset, ctxs_size;
+       char *u_spu_prio;
+       ulong spu_prio_addr, k_spu_prio, kvaddr, uvaddr, addr, ctx;
+       ulong *ctxs;
+       ulong list_head[2];
+       struct list_data list_data, *ld;
+
+       /* Walking SPUs */
+       for (i = 0; i < NR_SPUS; i++) {
+               addr = get_spu_addr(spu[i]) + CBE_OFFSET(spu, ctx);
+               readmem(addr, KVADDR, &ctx, sizeof(ctx), "show_ctx_info_all",
+                                                               FAULT_ON_ERROR);
+               show_ctx_info(ctx);
+       }
+
+       /* Walking SPU runqueue */
+       if (symbol_exists("spu_prio")) {
+               spu_prio_addr = symbol_value("spu_prio");
+               readmem(spu_prio_addr, KVADDR, &k_spu_prio, sizeof(k_spu_prio),
+                                               "runq_array", FAULT_ON_ERROR);
+       }
+       else
+               error(FATAL, "Could not get SPU run queue data.\n");
+
+       jump = CBE_SIZE(list_head);
+       prio_runq_off =  CBE_OFFSET(spu_prio_array, runq);
+       ctx_rq_off =  CBE_OFFSET(spu_context, rq);
+       prio_size = CBE_SIZE(spu_prio_array);
+
+       u_spu_prio = (char *)GETBUF(prio_size);
+       readmem(k_spu_prio, KVADDR, u_spu_prio, prio_size, "get_runq_ctxs", 
+                                                               FAULT_ON_ERROR);
+
+       for (i = 0; i < MAX_PRIO; i++) {
+               offset = prio_runq_off + i * jump;
+               kvaddr = k_spu_prio + offset;
+               uvaddr = (ulong)u_spu_prio + offset;
+
+               BCOPY((char *)uvaddr, (char *)&list_head[0], sizeof(ulong)*2);
+
+               if ((list_head[0] == kvaddr) && (list_head[1] == kvaddr))
+                       continue;
+
+               ld = &list_data;
+
+               BZERO(ld, sizeof(struct list_data));
+               ld->start = list_head[0];
+               ld->list_head_offset = ctx_rq_off;
+               ld->flags |= RETURN_ON_LIST_ERROR;
+               ld->end = kvaddr;
+
+               hq_open();
+               cnt = do_list(ld);
+               if (cnt == -1) {
+                       hq_close();
+                       FREEBUF(u_spu_prio);
+                       error(FATAL, "Couldn't walk the list.\n");
+               }
+
+               ctxs_size = cnt * sizeof(ulong);
+               ctxs = (ulong *)GETBUF(ctxs_size);
+
+               BZERO(ctxs, ctxs_size);
+               cnt = retrieve_list(ctxs, cnt);
+               hq_close();
+
+               for (j = 0; j < cnt; j++)
+                       show_ctx_info(ctxs[j]);
+
+               FREEBUF(ctxs);
+       }
+
+       FREEBUF(u_spu_prio);
+}
+
+/*
+ * Tries to discover the meaning of string and to find the referred context
+ */
+int str_to_spuctx(char *string, ulong *value, ulong *spu_ctx)
+{
+       char *s, *u_spu_prio;
+       ulong dvalue, hvalue, addr, ctx;
+       ulong k_spu_prio, spu_prio_addr, kvaddr, uvaddr;
+       int type, pid, i, j, cnt;
+       long prio_size, prio_runq_off, ctx_rq_off, jump, offset, ctxs_size;
+       ulong *ctxs;
+       ulong list_head[2];
+       struct list_data list_data, *ld;
+
+       if (string == NULL) {
+               error(INFO, "%s: received NULL string.\n", __FUNCTION__);
+               return STR_SPU_INVALID;
+       }
+
+       s = string;
+       dvalue = hvalue = BADADDR;
+
+       if (decimal(s, 0))
+               dvalue = dtol(s, RETURN_ON_ERROR, NULL);
+
+       if (hexadecimal(s, 0)) {
+               if (STRNEQ(s, "0x") || STRNEQ(s, "0X"))
+                       s += 2;
+               if (strlen(s) <= MAX_HEXADDR_STRLEN)
+                       hvalue = htol(s, RETURN_ON_ERROR, NULL);
+       }
+
+       type = STR_SPU_INVALID;
+
+       if (dvalue != BADADDR) {
+               /* Testing for SPU ID */
+               if ((dvalue >= 0) && (dvalue < NR_SPUS)) {
+                       addr = get_spu_addr(spu[dvalue]) + CBE_OFFSET(spu, ctx);
+                       readmem(addr, KVADDR, &ctx, sizeof(ctx), 
+                                       "str_to_spuctx ID", FAULT_ON_ERROR);
+
+                       type = STR_SPU_ID;
+                       *value = dvalue;
+                       *spu_ctx = ctx;
+                       return type;
+               }
+               else {
+                       /* Testing for PID */
+                       for (i = 0; i < NR_SPUS; i++) {
+                               addr = get_spu_addr(spu[i]) + 
+                                                       CBE_OFFSET(spu, pid);
+                               readmem(addr, KVADDR, &pid, sizeof(pid), 
+                                       "str_to_spuctx PID", FAULT_ON_ERROR);
+
+                               if (dvalue == pid) {
+                                       addr = get_spu_addr(spu[i]) +
+                                                       CBE_OFFSET(spu, ctx);
+                                       readmem(addr, KVADDR, &ctx, sizeof(ctx),
+                                               "str_to_spuctx PID ctx",
+                                               FAULT_ON_ERROR);
+
+                                       type = STR_SPU_PID;
+                                       *value = dvalue;
+                                       *spu_ctx = ctx;
+                                       return type;
+                               }
+                       }
+               }
+       }
+
+       if (hvalue != BADADDR) {
+               /* Testing for spuctx address on SPUs */
+               for (i = 0; i < NR_SPUS; i++) {
+                       addr = get_spu_addr(spu[i]) + CBE_OFFSET(spu, ctx);
+                       readmem(addr, KVADDR, &ctx, sizeof(ctx), 
+                                       "str_to_spuctx CTX", FAULT_ON_ERROR);
+
+                       if (hvalue == ctx) {
+                               type = STR_SPU_CTX_ADDR;
+                               *value = hvalue;
+                               *spu_ctx = ctx;
+                               return type;
+                       }
+               }
+
+               /* Testing for spuctx address on SPU runqueue */
+               if (symbol_exists("spu_prio")) {
+                       spu_prio_addr = symbol_value("spu_prio");
+                       readmem(spu_prio_addr, KVADDR, &k_spu_prio, 
+                             sizeof(k_spu_prio), "runq_array", FAULT_ON_ERROR);
+               }
+               else
+                       error(FATAL, "Could not get SPU run queue data.\n");
+
+               jump = CBE_SIZE(list_head);
+               prio_runq_off = CBE_OFFSET(spu_prio_array, runq);
+               ctx_rq_off = CBE_OFFSET(spu_context, rq);
+               prio_size = CBE_SIZE(spu_prio_array);
+
+               u_spu_prio = (char *)GETBUF(prio_size);
+               readmem(k_spu_prio, KVADDR, u_spu_prio, prio_size, 
+                                       "get_runq_ctxs", FAULT_ON_ERROR);
+
+               for (i = 0; i < MAX_PRIO; i++) {
+                       offset = prio_runq_off + i * jump;
+                       kvaddr = k_spu_prio + offset;
+                       uvaddr = (ulong)u_spu_prio + offset;
+
+                       BCOPY((char *)uvaddr, (char *)&list_head[0], 
sizeof(ulong)*2);
+
+                       if ((list_head[0] == kvaddr) && (list_head[1] == 
kvaddr))
+                               continue;
+
+                       ld = &list_data;
+
+                       BZERO(ld, sizeof(struct list_data));
+                       ld->start = list_head[0];
+                       ld->list_head_offset = ctx_rq_off;
+                       ld->flags |= RETURN_ON_LIST_ERROR;
+                       ld->end = kvaddr;
+
+                       hq_open();
+                       cnt = do_list(ld);
+                       if (cnt == -1) {
+                               hq_close();
+                               FREEBUF(u_spu_prio);
+                               error(FATAL, "Couldn't walk the list.\n");
+                       }
+
+                       ctxs_size = cnt * sizeof(ulong);
+                       ctxs = (ulong *)GETBUF(ctxs_size);
+                       
+                       BZERO(ctxs, ctxs_size);
+                       cnt = retrieve_list(ctxs, cnt);
+                       hq_close();
+
+                       for (j = 0; j < cnt; j++)
+                               if (hvalue == ctxs[j]) {
+                                       type = STR_SPU_CTX_ADDR;
+                                       *value = hvalue;
+                                       *spu_ctx = ctxs[j];
+                                       FREEBUF(u_spu_prio);
+                                       FREEBUF(ctxs);
+                                       return type;
+                               }
+
+                       FREEBUF(ctxs);
+               }
+
+               FREEBUF(u_spu_prio);
+       }
+
+       return type;
+}
+
+/* 
+ * spuctx command stands for "spu context" and shows the context fields 
+ * for the spu or respective struct address passed as an argument
+ */
+void cmd_spuctx()
+{
+       int i, c, cnt;
+       ulong value, ctx;
+       ulong *ctxlist;
+
+       while ((c = getopt(argcnt, args, "")) != EOF) {
+               switch(c) 
+               {
+               default:
+                       argerrs++;
+                       break;
+               }
+       }
+
+       if (argerrs)
+               cmd_usage(pc->curcmd, SYNOPSIS);
+
+       if (!args[optind]) {
+               show_ctx_info_all();
+               return;
+       }
+
+       cnt = 0;
+       ctxlist = (ulong *)GETBUF((MAXARGS+NR_CPUS)*sizeof(ctx));
+
+       while (args[optind]) {
+               if (IS_A_NUMBER(args[optind])) {
+                       switch (str_to_spuctx(args[optind], &value, &ctx)) 
+                       {
+                       case STR_SPU_ID:
+                       case STR_SPU_PID:
+                       case STR_SPU_CTX_ADDR:
+                               ctxlist[cnt++] = ctx;
+                               break;
+
+                       case STR_SPU_INVALID:
+                               error(INFO, "Invalid SPU reference: %s\n",
+                                                               args[optind]);
+                               break;
+                       }
+               }
+               else
+                       error(INFO, "Invalid SPU reference: %s\n", 
+                                                               args[optind]);
+               optind++;
+       }
+
+       if (cnt == 0)
+               error(INFO, "No valid ID, PID or context address.\n");
+       else
+               for (i = 0; i < cnt; i++)
+                       show_ctx_info(ctxlist[i]);
+
+       FREEBUF(ctxlist);
+}
+
+
+/*****************************************************************************
+ * SPUS COMMAND
+ */
+
+void print_spu_header(ulong spu_info)
+{
+       int id, pid, size, state;
+       uint status;
+       ulong ctx_addr, spu_addr;
+       char *spu_data;
+       const char *state_str;
+
+       if (spu_info) {
+               readmem(spu_info + CBE_OFFSET(crash_spu_info, 
+                       saved_spu_status_R), KVADDR, &status, sizeof(status),
+                       "print_spu_header: get status", FAULT_ON_ERROR);
+
+               size = CBE_SIZE(spu);
+               spu_data = GETBUF(size);
+               spu_addr = get_spu_addr(spu_info);
+               readmem(spu_addr, KVADDR, spu_data, size, "SPU struct", 
+                                                               FAULT_ON_ERROR);
+
+               id = *(int *)(spu_data + CBE_OFFSET(spu, number));
+               ctx_addr = *(ulong *)(spu_data + CBE_OFFSET(spu, ctx));
+               pid = *(int *)(spu_data + CBE_OFFSET(spu, pid));
+
+               readmem(ctx_addr + CBE_OFFSET(spu_context, state), KVADDR,
+                       &state, sizeof(state), "print_spu_header get ctxstate",
+                       FAULT_ON_ERROR);
+
+               switch (state) {
+                       case 0: /* SPU_STATE_RUNNABLE */
+                               state_str = "RUNNABLE";
+                               break;
+
+                       case 1: /* SPU_STATE_SAVED */
+                               state_str = " SAVED  ";
+                               break;
+
+                       default:
+                               state_str = "UNKNOWN ";
+               }
+
+               fprintf(fp, "%2d   %16lx   %s   %16lx   %s   %5d\n", id, 
+                   spu_addr, 
+                   status % 2 ? "RUNNING" : (ctx_addr ? "STOPPED" : "  IDLE "),
+                   ctx_addr, state_str, pid);
+
+               FREEBUF(spu_data);
+       }
+}
+
+void print_node_header(int node)
+{
+       fprintf(fp, "\n");
+       fprintf(fp, "NODE %i:\n", node);
+       fprintf(fp, "ID        SPUADDR      SPUSTATUS       CTXADDR       \
+CTXSTATE    PID \n");
+}
+
+void show_spus()
+{
+       int i, j, nr_cpus, show_header, node;
+       ulong spu_addr, addr;
+       long offset;
+
+       nr_cpus = kt->kernel_NR_CPUS ? kt->kernel_NR_CPUS : NR_CPUS;
+
+       for (i = 0; i < nr_cpus; i++) {
+               show_header = TRUE;
+
+               for (j = 0; j < NR_SPUS; j++) {
+                       addr = spu[j] + CBE_OFFSET(crash_spu_info, spu);
+                       readmem(addr, KVADDR, &spu_addr, sizeof(spu_addr),
+                                       "show_spus spu_addr", FAULT_ON_ERROR);
+
+                       offset = CBE_OFFSET(spu, node);
+                       if (offset == -1)
+                               error(FATAL, "Couldn't get spu.node offset.\n");
+
+                       spu_addr += offset;
+                       readmem(spu_addr, KVADDR, &node, sizeof(node),
+                                       "show_spus node", FAULT_ON_ERROR);
+
+                       if (node == i) {
+                               if (show_header) {
+                                       print_node_header(node);
+                                       show_header = FALSE;
+                               }
+
+                               print_spu_header(spu[j]);
+                       }
+               }
+       }
+}
+
+/*
+ * spus stands for "spu state" and shows what contexts are running in what 
+ * SPU.
+ */
+void cmd_spus()
+{
+       int c;
+
+       while ((c = getopt(argcnt, args, "")) != EOF) {
+               switch(c)
+               {
+               default:
+                       argerrs++;
+                       break;
+               }
+       }
+
+       if (argerrs || args[optind])
+               cmd_usage(pc->curcmd, SYNOPSIS);
+       else
+               show_spus();
+}
+
+
+/*****************************************************************************
+ * SPURQ COMMAND
+ */
+
+/*
+ * Prints the addresses of SPU contexts on the SPU runqueue.
+ */
+void dump_spu_runq(ulong k_spu_prio)
+{
+       int i, cnt;
+       long prio_size, prio_runq_off, ctx_rq_off, jump, offset;
+       char *u_spu_prio;
+       ulong kvaddr, uvaddr;
+       ulong list_head[2];
+       struct list_data list_data, *ld;
+
+       prio_runq_off = CBE_OFFSET(spu_prio_array, runq);
+       jump = CBE_SIZE(list_head);
+       ctx_rq_off = CBE_OFFSET(spu_context, rq);
+       prio_size = CBE_SIZE(spu_prio_array);
+
+       u_spu_prio = (char *)GETBUF(prio_size);
+       readmem(k_spu_prio, KVADDR, u_spu_prio, prio_size, "get_runq_ctxs", 
+                                                               FAULT_ON_ERROR);
+
+       for (i = 0; i < MAX_PRIO; i++) {
+               offset = prio_runq_off + (i * jump);
+               kvaddr = k_spu_prio + offset;
+               uvaddr = (ulong)u_spu_prio + offset;
+
+               BCOPY((char *)uvaddr, (char *)&list_head[0], sizeof(ulong)*2);
+
+               if ((list_head[0] == kvaddr) && (list_head[1] == kvaddr))
+                       continue;
+
+               fprintf(fp, "PRIO[%i]:\n", i);
+
+               ld = &list_data;
+
+               BZERO(ld, sizeof(struct list_data));
+               ld->start = list_head[0];
+               ld->list_head_offset = ctx_rq_off;
+               ld->flags |= VERBOSE;
+               ld->end = kvaddr;
+
+               hq_open();
+               cnt = do_list(ld);
+               hq_close();
+
+               if (cnt == -1) {
+                       FREEBUF(u_spu_prio);
+                       error(FATAL, "Couldn't walk runqueue[%i].\n", i);
+               }
+       }
+
+       FREEBUF(u_spu_prio);
+}
+
+/*
+ * spurq stands for "spu run queue" and shows info about the contexts 
+ * that are on the SPU run queue
+ */
+void cmd_spurq()
+{
+       int c;
+       ulong spu_prio_addr, spu_prio;
+       long size;
+
+       while ((c = getopt(argcnt, args, "")) != EOF) {
+               switch(c)
+               {
+               default:
+                       argerrs++;
+                       break;
+               }
+       }
+
+       if (argerrs || args[optind])
+               cmd_usage(pc->curcmd, SYNOPSIS);
+       else {
+               if (symbol_exists("spu_prio")) {
+                       spu_prio_addr = symbol_value("spu_prio");
+                       readmem(spu_prio_addr, KVADDR, &spu_prio,
+                               sizeof(spu_prio), "runq_array", FAULT_ON_ERROR);
+                       dump_spu_runq(spu_prio);
+               } else
+                       error(FATAL, "Could not get SPU run queue data.\n");
+       }
+}
+
+/**********************************************************************************
+ * HELP TEXTS
+ */
+
+char *help_spuctx[] = {
+       SPUCTX_CMD_NAME,
+       "shows complete info about a SPU context",
+       "[ID | PID | CTXADDR] ...",
+ 
+       "  This command shows the fields of spu and spu_context structs for a ",
+       "SPU context, including debug info specially saved by kdump after a ",
+       "crash.",
+       "  By default, it shows info about all the contexts created by the ",
+       "system, including ones in the runqueue. To specify the contexts of ",
+       "interest, the PID of the controller task, ID of the SPU which the ",
+       "context is bound to or the address of spu_context struct can be used ",
+       "as parameters.",
+       "\nEXAMPLES",
+       "\n  Show info about contexts bound to SPUs 0 and 7, and the one ",
+       "controlled by thread whose PID is 1524:",
+       "\n    crash> spuctx 0 7 1524",
+       "\n    Dumping context fields for spu_context c00000003dcbdd80:",
+       "      state                   = 0",
+       "      prio                    = 120",
+       "      local_store             = 0xc000000039055840",
+       "      rq                      = 0xc00000003dcbe720",
+       "      node                    = 0",
+       "      number                  = 0",
+       "      pid                     = 1524",
+       "      name                    = spe",
+       "      slb_replace             = 0",
+       "      mm                      = 0xc0000000005dd700",
+       "      timestamp               = 0x10000566f",
+       "      class_0_pending         = 0",
+       "      problem                 = 0xd000080080210000",
+       "      priv2                   = 0xd000080080230000",
+       "      flags                   = 0",
+       "      saved_mfc_sr1_RW        = 59",
+       "      saved_mfc_dar           = 14987979559889612800",
+       "      saved_mfc_dsisr         = 0",
+       "      saved_spu_runcntl_RW    = 1",
+       "      saved_spu_status_R      = 1",
+       "      saved_spu_npc_RW        = 0",
+       "\n    Dumping context fields for spu_context c00000003dec4e80:",
+       "      state                   = 0",
+       "      prio                    = 120",
+       "      local_store             = 0xc00000003b1cea40",
+       "      rq                      = 0xc00000003dec5820",
+       "      node                    = 0",
+       "      number                  = 7",
+       "      pid                     = 1538",
+       "      name                    = spe",
+       "      slb_replace             = 0",
+       "      mm                      = 0xc0000000005d2b80",
+       "      timestamp               = 0x10000566f",
+       "      class_0_pending         = 0",
+       "      problem                 = 0xd000080080600000",
+       "      priv2                   = 0xd000080080620000",
+       "      flags                   = 0",
+       "      saved_mfc_sr1_RW        = 59",
+       "      saved_mfc_dar           = 14987979559896297472",
+       "      saved_mfc_dsisr         = 0",
+       "      saved_spu_runcntl_RW    = 1",
+       "      saved_spu_status_R      = 1",
+       "      saved_spu_npc_RW        = 0",
+       "\n    Dumping context fields for spu_context c00000003dcbdd80:",
+       "      state                   = 0",
+       "      prio                    = 120",
+       "      local_store             = 0xc000000039055840",
+       "      rq                      = 0xc00000003dcbe720",
+       "      node                    = 0",
+       "      number                  = 0",
+       "      pid                     = 1524",
+       "      name                    = spe",
+       "      slb_replace             = 0",
+       "      mm                      = 0xc0000000005dd700",
+       "      timestamp               = 0x10000566f",
+       "      class_0_pending         = 0",
+       "      problem                 = 0xd000080080210000",
+       "      priv2                   = 0xd000080080230000",
+       "      flags                   = 0",
+       "      saved_mfc_sr1_RW        = 59",
+       "      saved_mfc_dar           = 14987979559889612800",
+       "      saved_mfc_dsisr         = 0",
+       "      saved_spu_runcntl_RW    = 1",
+       "      saved_spu_status_R      = 1",
+       "      saved_spu_npc_RW        = 0",
+
+       "\n  Show info about the context whose struct spu_context address is ", 
+       "0xc00000003dcbed80:\n",
+       "crash> spuctx 0x00000003dcbed80",
+       "    ...",
+       NULL
+};
+
+
+char *help_spus[] = {
+       SPUS_CMD_NAME,
+       "shows how contexts are scheduled in the SPUs",
+       " ",
+       "  This command shows how the contexts are scheduled in the SPUs of ",
+       "each node. It provides info about the spu address, SPU status, the ",
+       "spu_context address, context state and spu_context addresses and the ",
+       "PID of controller thread for each SPU.",
+       "\nEXAMPLE",
+       "  Show SPU contexts:",
+       "\n    crash> spus",
+       "    NODE 0:",
+       "    ID        SPUADDR      SPUSTATUS       CTXADDR       CTXSTATE    
PID ",
+       "     0   c000000001fac880   RUNNING   c00000003dcbdd80   RUNNABLE    
1524",
+       "     1   c000000001faca80   RUNNING   c00000003bf34e00   RUNNABLE    
1528",
+       "     2   c000000001facc80   RUNNING   c00000003bf30e00   RUNNABLE    
1525",
+       "     3   c000000001face80   RUNNING   c000000039421d00   RUNNABLE    
1533",
+       "     4   c00000003ee29080   RUNNING   c00000003dec3e80   RUNNABLE    
1534",
+       "     5   c00000003ee28e80   RUNNING   c00000003bf32e00   RUNNABLE    
1526",
+       "     6   c00000003ee28c80   STOPPED   c000000039e5e700    SAVED      
1522",
+       "     7   c00000003ee2e080   RUNNING   c00000003dec4e80   RUNNABLE    
1538",
+       "\n    NODE 1:",
+       "    ID        SPUADDR      SPUSTATUS       CTXADDR       CTXSTATE    
PID ",
+       "     8   c00000003ee2de80   RUNNING   c00000003dcbed80   RUNNABLE    
1529",
+       "     9   c00000003ee2dc80   RUNNING   c00000003bf39e00   RUNNABLE    
1535",
+       "    10   c00000003ee2da80   RUNNING   c00000003bf3be00   RUNNABLE    
1521",
+       "    11   c000000001fad080   RUNNING   c000000039420d00   RUNNABLE    
1532",
+       "    12   c000000001fad280   RUNNING   c00000003bf3ee00   RUNNABLE    
1536",
+       "    13   c000000001fad480   RUNNING   c00000003dec2e80   RUNNABLE    
1539",
+       "    14   c000000001fad680   RUNNING   c00000003bf3ce00   RUNNABLE    
1537",
+       "    15   c000000001fad880   RUNNING   c00000003dec6e80   RUNNABLE    
1540",
+       NULL
+};
+
+
+char *help_spurq[] = {
+       SPURQ_CMD_NAME,
+       "shows contexts on the SPU runqueue",
+       " ",
+       "  This command shows info about all contexts waiting for execution ", 
+       "in the SPU runqueue. No parameter is needed.",
+       "\nEXAMPLE",
+       "  Show SPU runqueue:",
+       "\n    crash> spurq",
+       "    PRIO[120]:",
+       "    c000000000fd7380",
+       "    c00000003bf31e00",
+       "    PRIO[125]:",
+       "    c000000039422d00",
+       "    c00000000181eb80",
+       NULL
+};
+
diff -Nurp crash-4.0-4.3.orig/Makefile crash-4.0-4.3/Makefile
--- crash-4.0-4.3.orig/Makefile 2007-06-22 15:49:16.000000000 -0300
+++ crash-4.0-4.3/Makefile      2007-06-28 14:06:08.000000000 -0300
@@ -103,8 +103,9 @@ OBJECT_FILES=main.o tools.o global_data.
 # directory.
 
 EXTENSIONS=extensions
-EXTENSION_SOURCE_FILES=${EXTENSIONS}/Makefile ${EXTENSIONS}/echo.c 
${EXTENSIONS}/dminfo.c
-EXTENSION_OBJECT_FILES=echo.so dminfo.so 
+EXTENSION_SOURCE_FILES=${EXTENSIONS}/Makefile ${EXTENSIONS}/echo.c \
+                       ${EXTENSIONS}/dminfo.c ${EXTENSIONS}/spu.c
+EXTENSION_OBJECT_FILES=echo.so dminfo.so spu.so
 
 DAEMON_OBJECT_FILES=remote_daemon.o va_server.o va_server_v1.o \
        lkcd_common.o lkcd_v1.o lkcd_v2_v3.o lkcd_v5.o lkcd_v7.o lkcd_v8.o \


--
Crash-utility mailing list
[email protected]
https://www.redhat.com/mailman/listinfo/crash-utility

Reply via email to