linux-old/arch/s390x/kernel/debug.c
<<
>>
Prefs
   1/*
   2 *  arch/s390/kernel/debug.c
   3 *   S/390 debug facility
   4 *
   5 *    Copyright (C) 1999, 2000 IBM Deutschland Entwicklung GmbH,
   6 *                             IBM Corporation
   7 *    Author(s): Michael Holzheu (holzheu@de.ibm.com),
   8 *               Holger Smolinski (Holger.Smolinski@de.ibm.com)
   9 *
  10 *    Bugreports to: <Linux390@de.ibm.com>
  11 */
  12
  13#include <linux/config.h>
  14#include <linux/stddef.h>
  15#include <linux/kernel.h>
  16#include <linux/errno.h>
  17#include <linux/slab.h>
  18#include <linux/ctype.h>
  19#include <linux/version.h>
  20#include <asm/uaccess.h>
  21#include <asm/semaphore.h>
  22
  23#include <linux/module.h>
  24
  25#include <asm/debug.h>
  26
  27#define MIN(a,b) (((a)<(b))?(a):(b))
  28#define DEBUG_PROLOG_ENTRY -1
  29
  30/* typedefs */
  31
  32typedef struct file_private_info {
  33        loff_t offset;                  /* offset of last read in file */
  34        int    act_area;                /* number of last formated area */
  35        int    act_entry;               /* last formated entry (offset */
  36                                        /* relative to beginning of last */
  37                                        /* formated area) */ 
  38        size_t act_entry_offset;        /* up to this offset we copied */
  39                                        /* in last read the last formated */
  40                                        /* entry to userland */
  41        char   temp_buf[2048];          /* buffer for output */
  42        debug_info_t *debug_info_org;   /* original debug information */
  43        debug_info_t *debug_info_snap;  /* snapshot of debug information */
  44        struct debug_view *view;        /* used view of debug info */
  45} file_private_info_t;
  46
  47typedef struct
  48{
  49        char *string;
  50        /* 
  51         * This assumes that all args are converted into longs 
  52         * on L/390 this is the case for all types of parameter 
  53         * except of floats, and long long (32 bit) 
  54         *
  55         */
  56        long args[0];
  57} debug_sprintf_entry;
  58
  59
  60extern void tod_to_timeval(uint64_t todval, struct timeval *xtime);
  61
  62/* internal function prototyes */
  63
  64static int debug_init(void);
  65static ssize_t debug_output(struct file *file, char *user_buf,
  66                            size_t user_len, loff_t * offset);
  67static ssize_t debug_input(struct file *file, const char *user_buf,
  68                           size_t user_len, loff_t * offset);
  69static int debug_open(struct inode *inode, struct file *file);
  70static int debug_close(struct inode *inode, struct file *file);
  71static struct proc_dir_entry 
  72*debug_create_proc_dir_entry(struct proc_dir_entry *root,
  73                             const char *name, mode_t mode,
  74                             struct inode_operations *iops,
  75                             struct file_operations *fops);
  76static void debug_delete_proc_dir_entry(struct proc_dir_entry *root,
  77                                        struct proc_dir_entry *entry);
  78static debug_info_t*  debug_info_create(char *name, int page_order, int nr_areas, int buf_size);
  79static void debug_info_get(debug_info_t *);
  80static void debug_info_put(debug_info_t *);
  81static int debug_prolog_level_fn(debug_info_t * id,
  82                                 struct debug_view *view, char *out_buf);
  83static int debug_input_level_fn(debug_info_t * id, struct debug_view *view,
  84                                struct file *file, const char *user_buf,
  85                                size_t user_buf_size, loff_t * offset);
  86static int debug_input_flush_fn(debug_info_t * id, struct debug_view *view,
  87                                struct file *file, const char *user_buf,
  88                                size_t user_buf_size, loff_t * offset);
  89static int debug_hex_ascii_format_fn(debug_info_t * id, struct debug_view *view,
  90                                char *out_buf, const char *in_buf);
  91static int debug_raw_format_fn(debug_info_t * id,
  92                                 struct debug_view *view, char *out_buf,
  93                                 const char *in_buf);
  94static int debug_raw_header_fn(debug_info_t * id, struct debug_view *view,
  95                         int area, debug_entry_t * entry, char *out_buf);
  96
  97static int debug_sprintf_format_fn(debug_info_t * id, struct debug_view *view,
  98                                   char *out_buf, debug_sprintf_entry *curr_event);
  99
 100/* globals */
 101
 102struct debug_view debug_raw_view = {
 103        "raw",
 104        NULL,
 105        &debug_raw_header_fn,
 106        &debug_raw_format_fn,
 107        NULL,
 108        NULL
 109};
 110
 111struct debug_view debug_hex_ascii_view = {
 112        "hex_ascii",
 113        NULL,
 114        &debug_dflt_header_fn,
 115        &debug_hex_ascii_format_fn,
 116        NULL,
 117        NULL
 118};
 119
 120struct debug_view debug_level_view = {
 121        "level",
 122        &debug_prolog_level_fn,
 123        NULL,
 124        NULL,
 125        &debug_input_level_fn,
 126        NULL
 127};
 128
 129struct debug_view debug_flush_view = {
 130        "flush",
 131        NULL,
 132        NULL,
 133        NULL,
 134        &debug_input_flush_fn,
 135        NULL
 136};
 137
 138struct debug_view debug_sprintf_view = {
 139        "sprintf",
 140        NULL,
 141        &debug_dflt_header_fn,
 142        (debug_format_proc_t*)&debug_sprintf_format_fn,
 143        NULL,
 144        NULL
 145};
 146
 147
 148unsigned int debug_feature_version = __DEBUG_FEATURE_VERSION;
 149
 150/* static globals */
 151
 152static debug_info_t *debug_area_first = NULL;
 153static debug_info_t *debug_area_last = NULL;
 154#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,98))
 155static struct semaphore debug_lock = MUTEX;
 156#else
 157DECLARE_MUTEX(debug_lock);
 158#endif
 159
 160static int initialized = 0;
 161
 162static struct file_operations debug_file_ops = {
 163        read:    debug_output,
 164        write:   debug_input,   
 165        open:    debug_open,
 166        release: debug_close,
 167};
 168
 169static struct inode_operations debug_inode_ops = {
 170#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,98))
 171        default_file_ops: &debug_file_ops,      /* file ops */
 172#endif
 173};
 174
 175
 176static struct proc_dir_entry *debug_proc_root_entry;
 177
 178/* functions */
 179
 180/*
 181 * debug_info_alloc
 182 * - alloc new debug-info
 183 */
 184
 185static debug_info_t*  debug_info_alloc(char *name, int page_order,
 186                                        int nr_areas, int buf_size)
 187{
 188        debug_info_t* rc;
 189        int i;
 190
 191        /* alloc everything */
 192
 193        rc = (debug_info_t*) kmalloc(sizeof(debug_info_t), GFP_ATOMIC);
 194        if(!rc)
 195                goto fail_malloc_rc;
 196        rc->active_entry = (int*)kmalloc(nr_areas * sizeof(int), GFP_ATOMIC);
 197        if(!rc->active_entry)
 198                goto fail_malloc_active_entry;
 199        memset(rc->active_entry, 0, nr_areas * sizeof(int));
 200        rc->areas = (debug_entry_t **) kmalloc(nr_areas *
 201                                                sizeof(debug_entry_t *),
 202                                                GFP_ATOMIC);
 203        if (!rc->areas)
 204                goto fail_malloc_areas;
 205        for (i = 0; i < nr_areas; i++) {
 206                rc->areas[i] = (debug_entry_t *) __get_free_pages(GFP_ATOMIC,
 207                                                                page_order);
 208                if (!rc->areas[i]) {
 209                        for (i--; i >= 0; i--) {
 210                                free_pages((unsigned long) rc->areas[i],
 211                                                page_order);
 212                        }
 213                        goto fail_malloc_areas2;
 214                } else {
 215                        memset(rc->areas[i], 0, PAGE_SIZE << page_order);
 216                }
 217        }
 218
 219        /* initialize members */
 220
 221        spin_lock_init(&rc->lock);
 222        rc->page_order  = page_order;
 223        rc->nr_areas    = nr_areas;
 224        rc->active_area = 0;
 225        rc->level       = DEBUG_DEFAULT_LEVEL;
 226        rc->buf_size    = buf_size;
 227        rc->entry_size  = sizeof(debug_entry_t) + buf_size;
 228        strncpy(rc->name, name, MIN(strlen(name), (DEBUG_MAX_PROCF_LEN - 1)));
 229        rc->name[MIN(strlen(name), (DEBUG_MAX_PROCF_LEN - 1))] = 0;
 230        memset(rc->views, 0, DEBUG_MAX_VIEWS * sizeof(struct debug_view *));
 231#ifdef CONFIG_PROC_FS
 232        memset(rc->proc_entries, 0 ,DEBUG_MAX_VIEWS *
 233                sizeof(struct proc_dir_entry*));
 234#endif /* CONFIG_PROC_FS */
 235        atomic_set(&(rc->ref_count), 0);
 236
 237        return rc;
 238
 239fail_malloc_areas2:
 240        kfree(rc->areas);
 241fail_malloc_areas:
 242        kfree(rc->active_entry);
 243fail_malloc_active_entry:
 244        kfree(rc);
 245fail_malloc_rc:
 246        return NULL;
 247}
 248
 249/*
 250 * debug_info_free
 251 * - free memory debug-info
 252 */
 253
 254static void debug_info_free(debug_info_t* db_info){
 255        int i;
 256        for (i = 0; i < db_info->nr_areas; i++) {
 257                free_pages((unsigned long) db_info->areas[i],
 258                db_info->page_order);
 259        }
 260        kfree(db_info->areas);
 261        kfree(db_info->active_entry);
 262        kfree(db_info);
 263}
 264
 265/*
 266 * debug_info_create
 267 * - create new debug-info
 268 */
 269
 270static debug_info_t*  debug_info_create(char *name, int page_order, 
 271                                        int nr_areas, int buf_size)
 272{
 273        debug_info_t* rc;
 274
 275        rc = debug_info_alloc(name, page_order, nr_areas, buf_size);
 276        if(!rc) 
 277                goto out;
 278
 279
 280        /* create proc rood directory */
 281
 282        rc->proc_root_entry =
 283            debug_create_proc_dir_entry(debug_proc_root_entry, rc->name,
 284                                        S_IFDIR | S_IRUGO | S_IXUGO |
 285                                        S_IWUSR | S_IWGRP, NULL, NULL);
 286
 287        /* append new element to linked list */
 288
 289        if(debug_area_first == NULL){
 290                /* first element in list */
 291                debug_area_first = rc;
 292                rc->prev = NULL;
 293        }
 294        else{
 295                /* append element to end of list */
 296                debug_area_last->next = rc;
 297                rc->prev = debug_area_last;
 298        }
 299        debug_area_last = rc;
 300        rc->next = NULL;
 301
 302        debug_info_get(rc);
 303out:
 304        return rc;
 305}
 306
 307/*
 308 * debug_info_copy
 309 * - copy debug-info
 310 */
 311
 312static debug_info_t* debug_info_copy(debug_info_t* in)
 313{
 314        int i;
 315        debug_info_t* rc;
 316        rc = debug_info_alloc(in->name, in->page_order, 
 317                                in->nr_areas, in->buf_size);
 318        if(!rc)
 319                goto out;
 320
 321        for(i = 0; i < in->nr_areas; i++){
 322                memcpy(rc->areas[i],in->areas[i], PAGE_SIZE << in->page_order);
 323        }
 324out:
 325        return rc;
 326}
 327
 328/*
 329 * debug_info_get
 330 * - increments reference count for debug-info
 331 */
 332
 333static void debug_info_get(debug_info_t * db_info)
 334{
 335        if (db_info)
 336                atomic_inc(&db_info->ref_count);
 337}
 338
 339/*
 340 * debug_info_put:
 341 * - decreases reference count for debug-info and frees it if necessary
 342 */
 343
 344static void debug_info_put(debug_info_t *db_info)
 345{
 346        int i;
 347
 348        if (!db_info)
 349                return;
 350        if (atomic_dec_and_test(&db_info->ref_count)) {
 351#ifdef DEBUG
 352                printk(KERN_INFO "debug: freeing debug area %p (%s)\n",
 353                       db_info, db_info->name);
 354#endif
 355                for (i = 0; i < DEBUG_MAX_VIEWS; i++) {
 356                        if (db_info->views[i] != NULL)
 357                                debug_delete_proc_dir_entry
 358                                    (db_info->proc_root_entry,
 359                                     db_info->proc_entries[i]);
 360                }
 361                debug_delete_proc_dir_entry(debug_proc_root_entry,
 362                                            db_info->proc_root_entry);
 363                if(db_info == debug_area_first)
 364                        debug_area_first = db_info->next;
 365                if(db_info == debug_area_last)
 366                        debug_area_last = db_info->prev;
 367                if(db_info->prev) db_info->prev->next = db_info->next;
 368                if(db_info->next) db_info->next->prev = db_info->prev;
 369                debug_info_free(db_info);
 370        }
 371}
 372
 373/*
 374 * debug_format_entry:
 375 * - format one debug entry and return size of formated data
 376 */
 377
 378static int debug_format_entry(file_private_info_t *p_info)
 379{
 380        debug_info_t *id_org    = p_info->debug_info_org;
 381        debug_info_t *id_snap   = p_info->debug_info_snap;
 382        struct debug_view *view = p_info->view;
 383        debug_entry_t *act_entry;
 384        size_t len = 0;
 385        if(p_info->act_entry == DEBUG_PROLOG_ENTRY){
 386                /* print prolog */
 387                if (view->prolog_proc)
 388                        len += view->prolog_proc(id_org, view,p_info->temp_buf);
 389                goto out;
 390        }
 391
 392        act_entry = (debug_entry_t *) ((char*)id_snap->areas[p_info->act_area] +
 393                                        p_info->act_entry);
 394                        
 395        if (act_entry->id.stck == 0LL)
 396                        goto out;  /* empty entry */
 397        if (view->header_proc)
 398                len += view->header_proc(id_org, view, p_info->act_area, 
 399                                        act_entry, p_info->temp_buf + len);
 400        if (view->format_proc)
 401                len += view->format_proc(id_org, view, p_info->temp_buf + len,
 402                                                DEBUG_DATA(act_entry));
 403      out:
 404        return len;
 405}
 406
 407/*
 408 * debug_next_entry:
 409 * - goto next entry in p_info
 410 */
 411
 412extern inline int debug_next_entry(file_private_info_t *p_info)
 413{
 414        debug_info_t *id = p_info->debug_info_snap;
 415        if(p_info->act_entry == DEBUG_PROLOG_ENTRY){
 416                p_info->act_entry = 0;
 417                goto out;
 418        }
 419        if ((p_info->act_entry += id->entry_size)
 420                > ((PAGE_SIZE << (id->page_order)) 
 421                - id->entry_size)){
 422
 423                /* next area */
 424                p_info->act_entry = 0;
 425                p_info->act_area++;
 426                if(p_info->act_area >= id->nr_areas)
 427                        return 1;
 428        }
 429out:
 430        return 0;       
 431}
 432
 433/*
 434 * debug_output:
 435 * - called for user read()
 436 * - copies formated debug entries to the user buffer
 437 */
 438
 439static ssize_t debug_output(struct file *file,  /* file descriptor */
 440                            char *user_buf,     /* user buffer */
 441                            size_t  len,        /* length of buffer */
 442                            loff_t *offset      /* offset in the file */ )
 443{
 444        size_t count = 0;
 445        size_t entry_offset, size = 0;
 446        int rc;
 447        file_private_info_t *p_info;
 448
 449        p_info = ((file_private_info_t *) file->private_data);
 450        if (*offset != p_info->offset) 
 451                return -EPIPE;
 452        if(p_info->act_area >= p_info->debug_info_snap->nr_areas)
 453                return 0;
 454
 455        entry_offset = p_info->act_entry_offset;
 456
 457        while(count < len){
 458                size = debug_format_entry(p_info);
 459                size = MIN((len - count), (size - entry_offset));
 460
 461                if(size){
 462                        if (copy_to_user(user_buf + count, 
 463                                        p_info->temp_buf + entry_offset, size))
 464                                return -EFAULT;
 465                }
 466                count += size;
 467                entry_offset = 0;
 468                if(count != len)
 469                        if(debug_next_entry(p_info)) 
 470                                goto out;
 471        }
 472out:
 473        p_info->offset           += count;
 474        p_info->act_entry_offset = size;        
 475        *offset = p_info->offset;
 476        return count;
 477}
 478
 479/*
 480 * debug_input:
 481 * - called for user write()
 482 * - calls input function of view
 483 */
 484
 485static ssize_t debug_input(struct file *file,
 486                           const char *user_buf, size_t length,
 487                           loff_t *offset)
 488{
 489        int rc = 0;
 490        file_private_info_t *p_info;
 491
 492        down(&debug_lock);
 493        p_info = ((file_private_info_t *) file->private_data);
 494        if (p_info->view->input_proc)
 495                rc = p_info->view->input_proc(p_info->debug_info_org,
 496                                              p_info->view, file, user_buf,
 497                                              length, offset);
 498        else
 499                rc = -EPERM;
 500        up(&debug_lock);
 501        return rc;              /* number of input characters */
 502}
 503
 504/*
 505 * debug_open:
 506 * - called for user open()
 507 * - copies formated output to private_data area of the file
 508 *   handle
 509 */
 510
 511static int debug_open(struct inode *inode, struct file *file)
 512{
 513        int i = 0, rc = 0;
 514        file_private_info_t *p_info;
 515        debug_info_t *debug_info, *debug_info_snapshot;
 516
 517#ifdef DEBUG
 518        printk("debug_open\n");
 519#endif
 520        MOD_INC_USE_COUNT;
 521        down(&debug_lock);
 522
 523        /* find debug log and view */
 524
 525        debug_info = debug_area_first;
 526        while(debug_info != NULL){
 527                for (i = 0; i < DEBUG_MAX_VIEWS; i++) {
 528                        if (debug_info->views[i] == NULL)
 529                                continue;
 530                        else if (debug_info->proc_entries[i]->low_ino ==
 531                                 file->f_dentry->d_inode->i_ino) {
 532                                goto found;     /* found view ! */
 533                        }
 534                }
 535                debug_info = debug_info->next;
 536        }
 537        /* no entry found */
 538        rc = -EINVAL;
 539        goto out;
 540
 541      found:
 542
 543        /* make snapshot of current debug areas to get it consistent */
 544
 545        debug_info_snapshot = debug_info_copy(debug_info);
 546
 547        if(!debug_info_snapshot){
 548#ifdef DEBUG
 549                printk(KERN_ERR "debug_open: debug_info_copy failed (out of mem)\n");
 550#endif
 551                rc = -ENOMEM;
 552                goto out;
 553        }
 554
 555        if ((file->private_data =
 556             kmalloc(sizeof(file_private_info_t), GFP_ATOMIC)) == 0) {
 557#ifdef DEBUG
 558                printk(KERN_ERR "debug_open: kmalloc failed\n");
 559#endif
 560                debug_info_free(debug_info_snapshot);   
 561                rc = -ENOMEM;
 562                goto out;
 563        }
 564        p_info = (file_private_info_t *) file->private_data;
 565        p_info->offset = 0;
 566        p_info->debug_info_snap = debug_info_snapshot;
 567        p_info->debug_info_org  = debug_info;
 568        p_info->view = debug_info->views[i];
 569        p_info->act_area = 0;
 570        p_info->act_entry = DEBUG_PROLOG_ENTRY;
 571        p_info->act_entry_offset = 0;
 572
 573        debug_info_get(debug_info);
 574
 575      out:
 576        up(&debug_lock);
 577        if (rc != 0)
 578                MOD_DEC_USE_COUNT;
 579        return rc;
 580}
 581
 582/*
 583 * debug_close:
 584 * - called for user close()
 585 * - deletes  private_data area of the file handle
 586 */
 587
 588static int debug_close(struct inode *inode, struct file *file)
 589{
 590        file_private_info_t *p_info;
 591#ifdef DEBUG
 592        printk("debug_close\n");
 593#endif
 594        p_info = (file_private_info_t *) file->private_data;
 595        debug_info_free(p_info->debug_info_snap);
 596        debug_info_put(p_info->debug_info_org);
 597        kfree(file->private_data);
 598        MOD_DEC_USE_COUNT;
 599        return 0;               /* success */
 600}
 601
 602/*
 603 * debug_create_proc_dir_entry:
 604 * - initializes proc-dir-entry and registers it
 605 */
 606
 607static struct proc_dir_entry *debug_create_proc_dir_entry
 608    (struct proc_dir_entry *root, const char *name, mode_t mode,
 609     struct inode_operations *iops, struct file_operations *fops) 
 610{
 611        struct proc_dir_entry *rc = NULL;
 612
 613#ifdef CONFIG_PROC_FS
 614#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,98))
 615        const char *fn = name;
 616        int len;
 617        len = strlen(fn);
 618
 619        rc = (struct proc_dir_entry *) kmalloc(sizeof(struct proc_dir_entry)
 620                                               + len + 1, GFP_ATOMIC);
 621        if (!rc)
 622                goto out;
 623
 624        memset(rc, 0, sizeof(struct proc_dir_entry));
 625        memcpy(((char *) rc) + sizeof(*rc), fn, len + 1);
 626        rc->name = ((char *) rc) + sizeof(*rc);
 627        rc->namelen = len;
 628        rc->low_ino = 0, rc->mode = mode;
 629        rc->nlink = 1;
 630        rc->uid = 0;
 631        rc->gid = 0;
 632        rc->size = 0;
 633        rc->get_info = NULL;
 634        rc->ops = iops;
 635
 636        proc_register(root, rc);
 637#else
 638        rc = create_proc_entry(name, mode, root);
 639        if (!rc)
 640                goto out;
 641        if (fops)
 642                rc->proc_fops = fops;
 643#endif
 644
 645      out:
 646#endif /* CONFIG_PROC_FS */
 647        return rc;
 648}
 649
 650
 651/*
 652 * delete_proc_dir_entry:
 653 */
 654
 655static void debug_delete_proc_dir_entry
 656    (struct proc_dir_entry *root, struct proc_dir_entry *proc_entry) 
 657{
 658
 659#ifdef CONFIG_PROC_FS
 660#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,98))
 661        proc_unregister(root, proc_entry->low_ino);
 662        kfree(proc_entry);
 663#else
 664        remove_proc_entry(proc_entry->name, root);
 665#endif
 666#endif /* CONFIG_PROC_FS */
 667}
 668
 669/*
 670 * debug_register:
 671 * - creates and initializes debug area for the caller
 672 * - returns handle for debug area
 673 */
 674
 675debug_info_t *debug_register
 676    (char *name, int page_order, int nr_areas, int buf_size) 
 677{
 678        debug_info_t *rc = NULL;
 679
 680        MOD_INC_USE_COUNT;
 681        if (!initialized)
 682                debug_init();
 683        down(&debug_lock);
 684
 685        /* create new debug_info */
 686
 687        rc = debug_info_create(name, page_order, nr_areas, buf_size);
 688        if(!rc) 
 689                goto out;
 690        debug_register_view(rc, &debug_level_view);
 691        debug_register_view(rc, &debug_flush_view);
 692#ifdef DEBUG
 693        printk(KERN_INFO
 694               "debug: reserved %d areas of %d pages for debugging %s\n",
 695               nr_areas, 1 << page_order, rc->name);
 696#endif
 697      out:
 698        if (rc == NULL){
 699                printk(KERN_ERR "debug: debug_register failed for %s\n",name);
 700                MOD_DEC_USE_COUNT;
 701        }
 702        up(&debug_lock);
 703        return rc;
 704}
 705
 706/*
 707 * debug_unregister:
 708 * - give back debug area
 709 */
 710
 711void debug_unregister(debug_info_t * id)
 712{
 713        if (!id)
 714                goto out;
 715        down(&debug_lock);
 716#ifdef DEBUG
 717        printk(KERN_INFO "debug: unregistering %s\n", id->name);
 718#endif
 719        debug_info_put(id);
 720        up(&debug_lock);
 721
 722        MOD_DEC_USE_COUNT;
 723      out:
 724        return;
 725}
 726
 727/*
 728 * debug_set_level:
 729 * - set actual debug level
 730 */
 731
 732void debug_set_level(debug_info_t* id, int new_level)
 733{
 734        unsigned long flags;
 735        if(!id)
 736                return; 
 737        spin_lock_irqsave(&id->lock,flags);
 738        if(new_level == DEBUG_OFF_LEVEL){
 739                id->level = DEBUG_OFF_LEVEL;
 740                printk(KERN_INFO "debug: %s: switched off\n",id->name);
 741        } else if ((new_level > DEBUG_MAX_LEVEL) || (new_level < 0)) {
 742                printk(KERN_INFO
 743                        "debug: %s: level %i is out of range (%i - %i)\n",
 744                        id->name, new_level, 0, DEBUG_MAX_LEVEL);
 745        } else {
 746                id->level = new_level;
 747#ifdef DEBUG
 748                printk(KERN_INFO 
 749                        "debug: %s: new level %i\n",id->name,id->level);
 750#endif
 751        }
 752        spin_unlock_irqrestore(&id->lock,flags);
 753}
 754
 755
 756/*
 757 * proceed_active_entry:
 758 * - set active entry to next in the ring buffer
 759 */
 760
 761extern inline void proceed_active_entry(debug_info_t * id)
 762{
 763        if ((id->active_entry[id->active_area] += id->entry_size)
 764            > ((PAGE_SIZE << (id->page_order)) - id->entry_size))
 765                id->active_entry[id->active_area] = 0;
 766}
 767
 768/*
 769 * proceed_active_area:
 770 * - set active area to next in the ring buffer
 771 */
 772
 773extern inline void proceed_active_area(debug_info_t * id)
 774{
 775        id->active_area++;
 776        id->active_area = id->active_area % id->nr_areas;
 777}
 778
 779/*
 780 * get_active_entry:
 781 */
 782
 783extern inline debug_entry_t *get_active_entry(debug_info_t * id)
 784{
 785        return (debug_entry_t *) ((char *) id->areas[id->active_area] +
 786                                  id->active_entry[id->active_area]);
 787}
 788
 789/*
 790 * debug_common:
 791 * - set timestamp, caller address, cpu number etc.
 792 */
 793
 794extern inline debug_entry_t *debug_common(debug_info_t * id, int level, 
 795                                    const void *buf, int len, int exception)
 796{
 797        unsigned long flags;
 798        debug_entry_t *active;
 799
 800        spin_lock_irqsave(&id->lock, flags);
 801        active = get_active_entry(id);
 802        STCK(active->id.stck);
 803        active->id.fields.cpuid = smp_processor_id();
 804        active->caller = __builtin_return_address(0);
 805        active->id.fields.exception = exception;
 806        active->id.fields.level     = level;
 807        memset(DEBUG_DATA(active), 0, id->buf_size);
 808        memcpy(DEBUG_DATA(active), buf, MIN(len, id->buf_size));
 809        proceed_active_entry(id);
 810        if(exception)
 811                proceed_active_area(id);
 812        spin_unlock_irqrestore(&id->lock, flags);
 813
 814        return active;
 815}
 816
 817/*
 818 * debug_event_common:
 819 * - write debug entry with given size
 820 */
 821
 822debug_entry_t *debug_event_common(debug_info_t * id, int level, const void *buf,
 823                                  int len)
 824{
 825        return debug_common(id, level, buf, len, 0);
 826}
 827
 828/*
 829 * debug_exception_common:
 830 * - write debug entry with given size and switch to next debug area
 831 */
 832
 833debug_entry_t *debug_exception_common(debug_info_t * id, int level, 
 834                                      const void *buf, int len)
 835{
 836        return debug_common(id, level, buf, len, 1);
 837}
 838
 839/*
 840 * counts arguments in format string for sprintf view
 841 */
 842
 843extern inline int debug_count_numargs(char *string)
 844{
 845        int numargs=0;
 846
 847        while(*string) {
 848                if(*string++=='%')
 849                        numargs++;
 850        }
 851        return(numargs);
 852}
 853
 854/*
 855 * debug_sprintf_event:
 856 */
 857
 858debug_entry_t *debug_sprintf_event(debug_info_t* id,
 859                                   int level,char *string,...)
 860{
 861        va_list   ap;
 862        int numargs,alloc_size,idx;
 863        debug_sprintf_entry *curr_event;
 864        debug_entry_t *retval = NULL;
 865
 866        if((!id) || (level > id->level))
 867                return NULL;
 868        else {
 869                numargs=debug_count_numargs(string);
 870                alloc_size=offsetof(debug_sprintf_entry,args[numargs]);
 871                curr_event=alloca(alloc_size);
 872
 873                if(curr_event){
 874                        va_start(ap,string);
 875                        curr_event->string=string;
 876                        for(idx=0;idx<numargs;idx++)
 877                                curr_event->args[idx]=va_arg(ap,long);
 878                        retval=debug_common(id,level, curr_event,alloc_size,0);
 879                        va_end(ap);
 880                }
 881                return retval;
 882        }
 883}
 884
 885/*
 886 * debug_sprintf_exception:
 887 */
 888
 889debug_entry_t *debug_sprintf_exception(debug_info_t* id,
 890                                       int level,char *string,...)
 891{
 892        va_list   ap;
 893        int numargs,alloc_size,idx;
 894        debug_sprintf_entry *curr_event;
 895        debug_entry_t *retval = NULL;
 896
 897        if((!id) || (level > id->level))
 898                return NULL;
 899        else {
 900                numargs=debug_count_numargs(string);
 901                alloc_size=offsetof(debug_sprintf_entry,args[numargs]);
 902                curr_event=alloca(alloc_size);
 903
 904                if(curr_event){
 905                        va_start(ap,string);
 906                        curr_event->string=string;
 907                        for(idx=0;idx<numargs;idx++)
 908                                curr_event->args[idx]=va_arg(ap,long);
 909                        retval=debug_common(id,level, curr_event,alloc_size,1);
 910                        va_end(ap);
 911                }
 912                return retval;
 913        }
 914}
 915
 916/*
 917 * debug_init:
 918 * - is called exactly once to initialize the debug feature
 919 */
 920
 921int debug_init(void)
 922{
 923        int rc = 0;
 924
 925        down(&debug_lock);
 926        if (!initialized) {
 927#ifdef CONFIG_PROC_FS
 928                debug_proc_root_entry =
 929                    debug_create_proc_dir_entry(&proc_root, DEBUG_DIR_ROOT,
 930                                                S_IFDIR | S_IRUGO | S_IXUGO
 931                                                | S_IWUSR | S_IWGRP, NULL,
 932                                                NULL);
 933#endif /* CONFIG_PROC_FS */
 934                printk(KERN_INFO "debug: Initialization complete\n");
 935                initialized = 1;
 936        }
 937        up(&debug_lock);
 938
 939        return rc;
 940}
 941
 942/*
 943 * debug_register_view:
 944 */
 945
 946int debug_register_view(debug_info_t * id, struct debug_view *view)
 947{
 948        int rc = 0;
 949        int i;
 950        unsigned long flags;
 951        mode_t mode = S_IFREG;
 952        struct proc_dir_entry *pde;
 953
 954
 955        if (!id)
 956                goto out;
 957        pde = debug_create_proc_dir_entry(id->proc_root_entry,
 958                                          view->name, mode,
 959                                          &debug_inode_ops,
 960                                          &debug_file_ops);
 961        if(!pde){
 962                printk(KERN_WARNING "debug: create_proc_entry() failed! Cannot register view %s/%s\n", id->name,view->name);
 963                rc = -1;
 964                goto out;
 965        }
 966
 967        spin_lock_irqsave(&id->lock, flags);
 968        for (i = 0; i < DEBUG_MAX_VIEWS; i++) {
 969                if (id->views[i] == NULL)
 970                        break;
 971        }
 972        if (i == DEBUG_MAX_VIEWS) {
 973                printk(KERN_WARNING "debug: cannot register view %s/%s\n",
 974                        id->name,view->name);
 975                printk(KERN_WARNING 
 976                        "debug: maximum number of views reached (%i)!\n", i);
 977                debug_delete_proc_dir_entry(id->proc_root_entry, pde);
 978                
 979                rc = -1;
 980        }
 981        else {
 982                id->views[i] = view;
 983                if (view->prolog_proc || view->format_proc || view->header_proc)
 984                        mode |= S_IRUSR;
 985                if (view->input_proc)
 986                        mode |= S_IWUSR;
 987                id->proc_entries[i] = pde;
 988                rc = 0;
 989        }
 990        spin_unlock_irqrestore(&id->lock, flags);
 991      out:
 992        return rc;
 993}
 994
 995/*
 996 * debug_unregister_view:
 997 */
 998
 999int debug_unregister_view(debug_info_t * id, struct debug_view *view)
1000{
1001        int rc = 0;
1002        int i;
1003        unsigned long flags;
1004
1005        if (!id)
1006                goto out;
1007        spin_lock_irqsave(&id->lock, flags);
1008        for (i = 0; i < DEBUG_MAX_VIEWS; i++) {
1009                if (id->views[i] == view)
1010                        break;
1011        }
1012        if (i == DEBUG_MAX_VIEWS)
1013                rc = -1;
1014        else {
1015                debug_delete_proc_dir_entry(id->proc_root_entry,
1016                                            id->proc_entries[i]);               
1017                id->views[i] = NULL;
1018                rc = 0;
1019        }
1020        spin_unlock_irqrestore(&id->lock, flags);
1021      out:
1022        return rc;
1023}
1024
1025/*
1026 * functions for debug-views
1027 ***********************************
1028*/
1029
1030/*
1031 * prints out actual debug level
1032 */
1033
1034static int debug_prolog_level_fn(debug_info_t * id,
1035                                 struct debug_view *view, char *out_buf)
1036{
1037        int rc = 0;
1038
1039        if(id->level == -1) rc = sprintf(out_buf,"-\n");
1040        else rc = sprintf(out_buf, "%i\n", id->level);
1041        return rc;
1042}
1043
1044/*
1045 * reads new debug level
1046 */
1047
1048static int debug_input_level_fn(debug_info_t * id, struct debug_view *view,
1049                                struct file *file, const char *user_buf,
1050                                size_t in_buf_size, loff_t * offset)
1051{
1052        char input_buf[1];
1053        int rc = in_buf_size;
1054
1055        if (*offset != 0)
1056                goto out;
1057        if (copy_from_user(input_buf, user_buf, 1)){
1058                rc = -EFAULT;
1059                goto out;
1060        }
1061        if (isdigit(input_buf[0])) {
1062                int new_level = ((int) input_buf[0] - (int) '0');
1063                debug_set_level(id, new_level);
1064        } else if(input_buf[0] == '-') {
1065                debug_set_level(id, DEBUG_OFF_LEVEL);
1066        } else {
1067                printk(KERN_INFO "debug: level `%c` is not valid\n",
1068                       input_buf[0]);
1069        }
1070      out:
1071        *offset = in_buf_size;
1072        return rc;              /* number of input characters */
1073}
1074
1075
1076/*
1077 * flushes debug areas
1078 */
1079 
1080void debug_flush(debug_info_t* id, int area)
1081{
1082        unsigned long flags;
1083        int i;
1084
1085        if(!id)
1086                return;
1087        spin_lock_irqsave(&id->lock,flags);
1088        if(area == DEBUG_FLUSH_ALL){
1089                id->active_area = 0;
1090                memset(id->active_entry, 0, id->nr_areas * sizeof(int));
1091                for (i = 0; i < id->nr_areas; i++) 
1092                        memset(id->areas[i], 0, PAGE_SIZE << id->page_order);
1093                printk(KERN_INFO "debug: %s: all areas flushed\n",id->name);
1094        } else if(area >= 0 && area < id->nr_areas) {
1095                id->active_entry[area] = 0;
1096                memset(id->areas[area], 0, PAGE_SIZE << id->page_order);
1097                printk(KERN_INFO
1098                        "debug: %s: area %i has been flushed\n",
1099                        id->name, area);
1100        } else {
1101                printk(KERN_INFO
1102                        "debug: %s: area %i cannot be flushed (range: %i - %i)\n",
1103                        id->name, area, 0, id->nr_areas-1);
1104        }
1105        spin_unlock_irqrestore(&id->lock,flags);
1106}
1107
1108/*
1109 * view function: flushes debug areas 
1110 */
1111 
1112static int debug_input_flush_fn(debug_info_t * id, struct debug_view *view,
1113                                struct file *file, const char *user_buf,
1114                                size_t in_buf_size, loff_t * offset)
1115{
1116        char input_buf[1];
1117        int rc = in_buf_size;
1118 
1119        if (*offset != 0)
1120                goto out;
1121        if (copy_from_user(input_buf, user_buf, 1)){
1122                rc = -EFAULT;
1123                goto out;
1124        }
1125        if(input_buf[0] == '-') { 
1126                debug_flush(id, DEBUG_FLUSH_ALL);
1127                goto out;
1128        }
1129        if (isdigit(input_buf[0])) {
1130                int area = ((int) input_buf[0] - (int) '0');
1131                debug_flush(id, area);
1132                goto out;
1133        }
1134
1135        printk(KERN_INFO "debug: area `%c` is not valid\n", input_buf[0]);
1136
1137      out:
1138        *offset = in_buf_size;
1139        return rc;              /* number of input characters */
1140}
1141
1142/*
1143 * prints debug header in raw format
1144 */
1145
1146int debug_raw_header_fn(debug_info_t * id, struct debug_view *view,
1147                         int area, debug_entry_t * entry, char *out_buf)
1148{
1149        int rc;
1150
1151        rc = sizeof(debug_entry_t);
1152        memcpy(out_buf,entry,sizeof(debug_entry_t));
1153        return rc;
1154}
1155
1156/*
1157 * prints debug data in raw format
1158 */
1159
1160static int debug_raw_format_fn(debug_info_t * id, struct debug_view *view,
1161                               char *out_buf, const char *in_buf)
1162{
1163        int rc;
1164
1165        rc = id->buf_size;
1166        memcpy(out_buf, in_buf, id->buf_size);
1167        return rc;
1168}
1169
1170/*
1171 * prints debug data in hex/ascii format
1172 */
1173
1174static int debug_hex_ascii_format_fn(debug_info_t * id, struct debug_view *view,
1175                                  char *out_buf, const char *in_buf)
1176{
1177        int i, rc = 0;
1178
1179        for (i = 0; i < id->buf_size; i++) {
1180                rc += sprintf(out_buf + rc, "%02x ",
1181                              ((unsigned char *) in_buf)[i]);
1182        }
1183        rc += sprintf(out_buf + rc, "| ");
1184        for (i = 0; i < id->buf_size; i++) {
1185                unsigned char c = in_buf[i];
1186                if (!isprint(c))
1187                        rc += sprintf(out_buf + rc, ".");
1188                else
1189                        rc += sprintf(out_buf + rc, "%c", c);
1190        }
1191        rc += sprintf(out_buf + rc, "\n");
1192        return rc;
1193}
1194
1195/*
1196 * prints header for debug entry
1197 */
1198
1199int debug_dflt_header_fn(debug_info_t * id, struct debug_view *view,
1200                         int area, debug_entry_t * entry, char *out_buf)
1201{
1202        struct timeval time_val;
1203        unsigned long long time;
1204        char *except_str;
1205        unsigned long caller;
1206        int rc = 0;
1207        unsigned int level;
1208
1209        level = entry->id.fields.level;
1210        time = entry->id.stck;
1211        /* adjust todclock to 1970 */
1212        time -= 0x8126d60e46000000LL - (0x3c26700LL * 1000000 * 4096);
1213        tod_to_timeval(time, &time_val);
1214
1215        if (entry->id.fields.exception)
1216                except_str = "*";
1217        else
1218                except_str = "-";
1219        caller = (unsigned long) entry->caller;
1220#if defined(CONFIG_ARCH_S390X)
1221        rc += sprintf(out_buf, "%02i %011lu:%06lu %1u %1s %02i %016lx  ",
1222                      area, time_val.tv_sec, time_val.tv_usec, level,
1223                      except_str, entry->id.fields.cpuid, caller);
1224#else
1225        caller &= 0x7fffffff;
1226        rc += sprintf(out_buf, "%02i %011lu:%06lu %1u %1s %02i %08lx  ",
1227                      area, time_val.tv_sec, time_val.tv_usec, level,
1228                      except_str, entry->id.fields.cpuid, caller);
1229#endif
1230        return rc;
1231}
1232
1233/*
1234 * prints debug data sprintf-formated:
1235 * debug_sprinf_event/exception calls must be used together with this view
1236 */
1237
1238#define DEBUG_SPRINTF_MAX_ARGS 10
1239
1240int debug_sprintf_format_fn(debug_info_t * id, struct debug_view *view,
1241                            char *out_buf, debug_sprintf_entry *curr_event)
1242{
1243        int num_longs, num_used_args = 0,i, rc = 0;
1244        int index[DEBUG_SPRINTF_MAX_ARGS];
1245
1246        /* count of longs fit into one entry */
1247        num_longs = id->buf_size /  sizeof(long); 
1248
1249        if(num_longs < 1)
1250                goto out; /* bufsize of entry too small */
1251        if(num_longs == 1) {
1252                /* no args, we use only the string */
1253                strcpy(out_buf, curr_event->string);
1254                rc = strlen(curr_event->string);
1255                goto out;
1256        }
1257
1258        /* number of arguments used for sprintf (without the format string) */
1259        num_used_args   = MIN(DEBUG_SPRINTF_MAX_ARGS, (num_longs - 1));
1260
1261        memset(index,0, DEBUG_SPRINTF_MAX_ARGS * sizeof(int));
1262
1263        for(i = 0; i < num_used_args; i++)
1264                index[i] = i;
1265
1266        rc =  sprintf(out_buf, curr_event->string, curr_event->args[index[0]],
1267                curr_event->args[index[1]], curr_event->args[index[2]],
1268                curr_event->args[index[3]], curr_event->args[index[4]],
1269                curr_event->args[index[5]], curr_event->args[index[6]],
1270                curr_event->args[index[7]], curr_event->args[index[8]],
1271                curr_event->args[index[9]]);
1272
1273out:
1274
1275        return rc;
1276}
1277
1278/*
1279 * init_module:
1280 */
1281
1282#ifdef MODULE
1283int init_module(void)
1284{
1285        int rc = 0;
1286#ifdef DEBUG
1287        printk("debug_module_init: \n");
1288#endif
1289        rc = debug_init();
1290        if (rc) 
1291                printk(KERN_INFO "debug: an error occurred with debug_init\n");
1292        return rc;
1293}
1294
1295/*
1296 * cleanup_module:
1297 */
1298
1299void cleanup_module(void)
1300{
1301#ifdef DEBUG
1302        printk("debug_cleanup_module: \n");
1303#endif
1304#ifdef CONFIG_PROC_FS
1305        debug_delete_proc_dir_entry(&proc_root, debug_proc_root_entry);
1306#endif /* CONFIG_PROC_FS */
1307        return;
1308}
1309
1310#endif                  /* MODULE */
1311
1312EXPORT_SYMBOL(debug_register);
1313EXPORT_SYMBOL(debug_unregister); 
1314EXPORT_SYMBOL(debug_set_level);
1315EXPORT_SYMBOL(debug_register_view);
1316EXPORT_SYMBOL(debug_unregister_view);
1317EXPORT_SYMBOL(debug_event_common);
1318EXPORT_SYMBOL(debug_exception_common);
1319EXPORT_SYMBOL(debug_hex_ascii_view);
1320EXPORT_SYMBOL(debug_raw_view);
1321EXPORT_SYMBOL(debug_dflt_header_fn);
1322EXPORT_SYMBOL(debug_sprintf_view);
1323EXPORT_SYMBOL(debug_sprintf_exception);
1324EXPORT_SYMBOL(debug_sprintf_event);
1325
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.