darwin-xnu/osfmk/i386/db_trace.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
   3 *
   4 * @APPLE_LICENSE_HEADER_START@
   5 * 
   6 * The contents of this file constitute Original Code as defined in and
   7 * are subject to the Apple Public Source License Version 1.1 (the
   8 * "License").  You may not use this file except in compliance with the
   9 * License.  Please obtain a copy of the License at
  10 * http://www.apple.com/publicsource and read it before using this file.
  11 * 
  12 * This Original Code and all software distributed under the License are
  13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
  16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
  17 * License for the specific language governing rights and limitations
  18 * under the License.
  19 * 
  20 * @APPLE_LICENSE_HEADER_END@
  21 */
  22/*
  23 * @OSF_COPYRIGHT@
  24 */
  25/* 
  26 * Mach Operating System
  27 * Copyright (c) 1991,1990 Carnegie Mellon University
  28 * All Rights Reserved.
  29 * 
  30 * Permission to use, copy, modify and distribute this software and its
  31 * documentation is hereby granted, provided that both the copyright
  32 * notice and this permission notice appear in all copies of the
  33 * software, derivative works or modified versions, and any portions
  34 * thereof, and that both notices appear in supporting documentation.
  35 * 
  36 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
  37 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
  38 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
  39 * 
  40 * Carnegie Mellon requests users of this software to return to
  41 * 
  42 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
  43 *  School of Computer Science
  44 *  Carnegie Mellon University
  45 *  Pittsburgh PA 15213-3890
  46 * 
  47 * any improvements or extensions that they make and grant Carnegie Mellon
  48 * the rights to redistribute these changes.
  49 */
  50/*
  51 */
  52
  53#include <string.h>
  54
  55#include <mach/boolean.h>
  56#include <vm/vm_map.h>
  57#include <kern/thread.h>
  58#include <kern/task.h>
  59
  60#include <machine/asm.h>
  61#include <machine/db_machdep.h>
  62#include <machine/setjmp.h>
  63#include <mach/machine.h>
  64
  65#include <ddb/db_access.h>
  66#include <ddb/db_sym.h>
  67#include <ddb/db_variables.h>
  68#include <ddb/db_command.h>
  69#include <ddb/db_task_thread.h>
  70#include <ddb/db_output.h>
  71
  72extern jmp_buf_t *db_recover;
  73extern struct i386_saved_state *saved_state[];
  74
  75struct i386_kernel_state ddb_null_kregs;
  76
  77/*
  78 * Stack trace.
  79 */
  80
  81extern vm_offset_t vm_min_inks_addr;    /* set by db_clone_symtabXXX */
  82#define INKSERVER(va)   (((vm_offset_t)(va)) >= vm_min_inks_addr)
  83
  84extern vm_offset_t interrupt_stack[];
  85#define ININTSTACK(va)                                          \
  86        (((vm_offset_t)(va)) >= interrupt_stack[cpu_number()] &&\
  87         (((vm_offset_t)(va)) < interrupt_stack[cpu_number()] + \
  88                                INTSTACK_SIZE))
  89
  90#define INKERNELSTACK(va, th)                                   \
  91        (th == THREAD_NULL ||                           \
  92         (((vm_offset_t)(va)) >= th->thread->kernel_stack &&    \
  93          (((vm_offset_t)(va)) < th->thread->kernel_stack +     \
  94                                 KERNEL_STACK_SIZE)) ||         \
  95         ININTSTACK(va))
  96
  97struct i386_frame {
  98        struct i386_frame       *f_frame;
  99        int                     f_retaddr;
 100        int                     f_arg0;
 101};
 102
 103#define TRAP            1
 104#define INTERRUPT       2
 105#define SYSCALL         3
 106
 107db_addr_t       db_user_trap_symbol_value = 0;
 108db_addr_t       db_kernel_trap_symbol_value = 0;
 109db_addr_t       db_interrupt_symbol_value = 0;
 110db_addr_t       db_return_to_iret_symbol_value = 0;
 111db_addr_t       db_syscall_symbol_value = 0;
 112boolean_t       db_trace_symbols_found = FALSE;
 113
 114struct i386_kregs {
 115        char    *name;
 116        int     offset;
 117} i386_kregs[] = {
 118        { "ebx", (int)(&((struct i386_kernel_state *)0)->k_ebx) },
 119        { "esp", (int)(&((struct i386_kernel_state *)0)->k_esp) },
 120        { "ebp", (int)(&((struct i386_kernel_state *)0)->k_ebp) },
 121        { "edi", (int)(&((struct i386_kernel_state *)0)->k_edi) },
 122        { "esi", (int)(&((struct i386_kernel_state *)0)->k_esi) },
 123        { "eip", (int)(&((struct i386_kernel_state *)0)->k_eip) },
 124        { 0 },
 125};
 126
 127/* Forward */
 128
 129extern int *    db_lookup_i386_kreg(
 130                        char                    *name,
 131                        int                     *kregp);
 132extern int      db_i386_reg_value(
 133                        struct db_variable      * vp,
 134                        db_expr_t               * val,
 135                        int                     flag,
 136                        db_var_aux_param_t      ap);
 137extern void     db_find_trace_symbols(void);
 138extern int      db_numargs(
 139                        struct i386_frame       *fp,
 140                        task_t                  task);
 141extern void     db_nextframe(
 142                        struct i386_frame       **lfp,
 143                        struct i386_frame       **fp,
 144                        db_addr_t               *ip,
 145                        int                     frame_type,
 146                        thread_t                thr_act);
 147extern int      _setjmp(
 148                        jmp_buf_t               * jb);
 149
 150/*
 151 * Machine register set.
 152 */
 153struct db_variable db_regs[] = {
 154        { "cs", (int *)&ddb_regs.cs,  db_i386_reg_value, 0, 0, 0, 0, TRUE },
 155        { "ds", (int *)&ddb_regs.ds,  db_i386_reg_value, 0, 0, 0, 0, TRUE },
 156        { "es", (int *)&ddb_regs.es,  db_i386_reg_value, 0, 0, 0, 0, TRUE },
 157        { "fs", (int *)&ddb_regs.fs,  db_i386_reg_value, 0, 0, 0, 0, TRUE },
 158        { "gs", (int *)&ddb_regs.gs,  db_i386_reg_value, 0, 0, 0, 0, TRUE },
 159        { "ss", (int *)&ddb_regs.ss,  db_i386_reg_value, 0, 0, 0, 0, TRUE },
 160        { "eax",(int *)&ddb_regs.eax, db_i386_reg_value, 0, 0, 0, 0, TRUE },
 161        { "ecx",(int *)&ddb_regs.ecx, db_i386_reg_value, 0, 0, 0, 0, TRUE },
 162        { "edx",(int *)&ddb_regs.edx, db_i386_reg_value, 0, 0, 0, 0, TRUE },
 163        { "ebx",(int *)&ddb_regs.ebx, db_i386_reg_value, 0, 0, 0, 0, TRUE },
 164        { "esp",(int *)&ddb_regs.uesp,db_i386_reg_value, 0, 0, 0, 0, TRUE },
 165        { "ebp",(int *)&ddb_regs.ebp, db_i386_reg_value, 0, 0, 0, 0, TRUE },
 166        { "esi",(int *)&ddb_regs.esi, db_i386_reg_value, 0, 0, 0, 0, TRUE },
 167        { "edi",(int *)&ddb_regs.edi, db_i386_reg_value, 0, 0, 0, 0, TRUE },
 168        { "eip",(int *)&ddb_regs.eip, db_i386_reg_value, 0, 0, 0, 0, TRUE },
 169        { "efl",(int *)&ddb_regs.efl, db_i386_reg_value, 0, 0, 0, 0, TRUE },
 170};
 171struct db_variable *db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]);
 172
 173int *
 174db_lookup_i386_kreg(
 175        char    *name,
 176        int     *kregp)
 177{
 178        register struct i386_kregs *kp;
 179
 180        for (kp = i386_kregs; kp->name; kp++) {
 181            if (strcmp(name, kp->name) == 0)
 182                return((int *)((int)kregp + kp->offset));
 183        }
 184        return(0);
 185}
 186        
 187int
 188db_i386_reg_value(
 189        struct  db_variable     *vp,
 190        db_expr_t               *valuep,
 191        int                     flag,
 192        db_var_aux_param_t      ap)
 193{
 194        extern char             etext;
 195        int                     *dp = 0;
 196        db_expr_t               null_reg = 0;
 197        register thread_t       thr_act = ap->thr_act;
 198        extern unsigned         int_stack_high;
 199        int                     cpu;
 200
 201        if (db_option(ap->modif, 'u')) {
 202            if (thr_act == THREAD_NULL) {
 203                if ((thr_act = current_thread()) == THREAD_NULL)
 204                    db_error("no user registers\n");
 205            }
 206            if (thr_act == current_thread()) {
 207                if (IS_USER_TRAP(&ddb_regs, &etext))
 208                    dp = vp->valuep;
 209                else if (ddb_regs.ebp < int_stack_high)
 210                    db_error("cannot get/set user registers in nested interrupt\n");
 211            }
 212        } else {
 213            if (thr_act == THREAD_NULL || thr_act == current_thread()) {
 214                dp = vp->valuep;
 215            } else {
 216              if (thr_act->thread &&
 217                  !(thr_act->thread->state & TH_STACK_HANDOFF) && 
 218                        thr_act->thread->kernel_stack) {
 219                int cpu;
 220
 221                for (cpu = 0; cpu < real_ncpus; cpu++) {
 222                    if (cpu_datap(cpu)->cpu_running == TRUE &&
 223                        cpu_datap(cpu)->cpu_active_thread == thr_act->thread && saved_state[cpu]) {
 224                        dp = (int *) (((int)saved_state[cpu]) +
 225                                      (((int) vp->valuep) -
 226                                       (int) &ddb_regs));
 227                        break;
 228                    }
 229                }
 230                if (dp == 0 && thr_act && thr_act->thread)
 231                    dp = db_lookup_i386_kreg(vp->name,
 232                         (int *)(STACK_IKS(thr_act->thread->kernel_stack)));
 233                if (dp == 0)
 234                    dp = &null_reg;
 235              } else if (thr_act->thread &&
 236                         (thr_act->thread->state&TH_STACK_HANDOFF)){
 237                /* only EIP is valid */
 238                if (vp->valuep == (int *) &ddb_regs.eip) {
 239                    dp = (int *)(&thr_act->thread->continuation);
 240                } else {
 241                    dp = &null_reg;
 242                }
 243              }
 244            }
 245        }
 246        if (dp == 0) {
 247            int cpu;
 248
 249            if (!db_option(ap->modif, 'u')) {
 250                for (cpu = 0; cpu < real_ncpus; cpu++) {
 251                    if (cpu_datap(cpu)->cpu_running == TRUE &&
 252                        cpu_datap(cpu)->cpu_active_thread == thr_act->thread && saved_state[cpu]) {
 253                            dp = (int *) (((int)saved_state[cpu]) +
 254                                          (((int) vp->valuep) -
 255                                           (int) &ddb_regs));
 256                            break;
 257                    }
 258                }
 259            }
 260            if (dp == 0) {
 261                if (!thr_act || thr_act->machine.pcb == 0)
 262                    db_error("no pcb\n");
 263                dp = (int *)((int)(&thr_act->machine.pcb->iss) + 
 264                             ((int)vp->valuep - (int)&ddb_regs));
 265            }
 266        }
 267        if (flag == DB_VAR_SET)
 268            *dp = *valuep;
 269        else
 270            *valuep = *dp;
 271        return(0);
 272}
 273
 274void
 275db_find_trace_symbols(void)
 276{
 277        db_expr_t       value;
 278        boolean_t       found_some;
 279
 280        found_some = FALSE;
 281        if (db_value_of_name(CC_SYM_PREFIX "user_trap", &value)) {
 282            db_user_trap_symbol_value = (db_addr_t) value;
 283            found_some = TRUE;
 284        }
 285        if (db_value_of_name(CC_SYM_PREFIX "kernel_trap", &value)) {
 286            db_kernel_trap_symbol_value = (db_addr_t) value;
 287            found_some = TRUE;
 288        }
 289        if (db_value_of_name(CC_SYM_PREFIX "interrupt", &value)) {
 290            db_interrupt_symbol_value = (db_addr_t) value;
 291            found_some = TRUE;
 292        }
 293        if (db_value_of_name(CC_SYM_PREFIX "return_to_iret", &value)) {
 294            db_return_to_iret_symbol_value = (db_addr_t) value;
 295            found_some = TRUE;
 296        }
 297        if (db_value_of_name(CC_SYM_PREFIX "syscall", &value)) {
 298            db_syscall_symbol_value = (db_addr_t) value;
 299            found_some = TRUE;
 300        }
 301        if (found_some) 
 302            db_trace_symbols_found = TRUE;
 303}
 304
 305/*
 306 * Figure out how many arguments were passed into the frame at "fp".
 307 */
 308int db_numargs_default = 5;
 309
 310int
 311db_numargs(
 312        struct i386_frame       *fp,
 313        task_t                  task)
 314{
 315        int     *argp;
 316        int     inst;
 317        int     args;
 318        extern char     etext;
 319
 320        argp = (int *)db_get_task_value((int)&fp->f_retaddr, 4, FALSE, task);
 321        if (argp < (int *)VM_MIN_KERNEL_ADDRESS || (char *)argp > &etext)
 322            args = db_numargs_default;
 323        else if (!DB_CHECK_ACCESS((int)argp, 4, task))
 324            args = db_numargs_default;
 325        else {
 326            inst = db_get_task_value((int)argp, 4, FALSE, task);
 327            if ((inst & 0xff) == 0x59)  /* popl %ecx */
 328                args = 1;
 329            else if ((inst & 0xffff) == 0xc483) /* addl %n, %esp */
 330                args = ((inst >> 16) & 0xff) / 4;
 331            else
 332                args = db_numargs_default;
 333        }
 334        return (args);
 335}
 336
 337struct interrupt_frame {
 338        struct i386_frame *if_frame;    /* point to next frame */
 339        int               if_retaddr;   /* return address to _interrupt */
 340        int               if_unit;      /* unit number */
 341        int               if_spl;       /* saved spl */
 342        int               if_iretaddr;  /* _return_to_{iret,iret_i} */
 343        int               if_edx;       /* old sp(iret) or saved edx(iret_i) */
 344        int               if_ecx;       /* saved ecx(iret_i) */
 345        int               if_eax;       /* saved eax(iret_i) */
 346        int               if_eip;       /* saved eip(iret_i) */
 347        int               if_cs;        /* saved cs(iret_i) */
 348        int               if_efl;       /* saved efl(iret_i) */
 349};
 350
 351/* 
 352 * Figure out the next frame up in the call stack.  
 353 * For trap(), we print the address of the faulting instruction and 
 354 *   proceed with the calling frame.  We return the ip that faulted.
 355 *   If the trap was caused by jumping through a bogus pointer, then
 356 *   the next line in the backtrace will list some random function as 
 357 *   being called.  It should get the argument list correct, though.  
 358 *   It might be possible to dig out from the next frame up the name
 359 *   of the function that faulted, but that could get hairy.
 360 */
 361void
 362db_nextframe(
 363        struct i386_frame       **lfp,          /* in/out */
 364        struct i386_frame       **fp,           /* in/out */
 365        db_addr_t               *ip,            /* out */
 366        int                     frame_type,     /* in */
 367        thread_t                thr_act)        /* in */
 368{
 369        extern char *   trap_type[];
 370        extern int      TRAP_TYPES;
 371
 372        struct i386_saved_state *saved_regs;
 373        struct interrupt_frame *ifp;
 374        struct i386_interrupt_state *isp;
 375        task_t task = (thr_act != THREAD_NULL)? thr_act->task: TASK_NULL;
 376
 377        switch(frame_type) {
 378        case TRAP:
 379            /*
 380             * We know that trap() has 1 argument and we know that
 381             * it is an (strcut i386_saved_state *).
 382             */
 383            saved_regs = (struct i386_saved_state *)
 384                        db_get_task_value((int)&((*fp)->f_arg0),4,FALSE,task);
 385            if (saved_regs->trapno >= 0 && saved_regs->trapno < TRAP_TYPES) {
 386                db_printf(">>>>> %s trap at ",
 387                        trap_type[saved_regs->trapno]);
 388            } else {
 389                db_printf(">>>>> trap (number %d) at ",
 390                        saved_regs->trapno & 0xffff);
 391            }
 392            db_task_printsym(saved_regs->eip, DB_STGY_PROC, task);
 393            db_printf(" <<<<<\n");
 394            *fp = (struct i386_frame *)saved_regs->ebp;
 395            *ip = (db_addr_t)saved_regs->eip;
 396            break;
 397        case INTERRUPT:
 398            if (*lfp == 0) {
 399                db_printf(">>>>> interrupt <<<<<\n");
 400                goto miss_frame;
 401            }
 402            db_printf(">>>>> interrupt at "); 
 403            ifp = (struct interrupt_frame *)(*lfp);
 404            *fp = ifp->if_frame;
 405            if (ifp->if_iretaddr == db_return_to_iret_symbol_value)
 406                *ip = ((struct i386_interrupt_state *) ifp->if_edx)->eip;
 407            else
 408                *ip = (db_addr_t) ifp->if_eip;
 409            db_task_printsym(*ip, DB_STGY_PROC, task);
 410            db_printf(" <<<<<\n");
 411            break;
 412        case SYSCALL:
 413            if (thr_act != THREAD_NULL && thr_act->machine.pcb) {
 414                *ip = (db_addr_t) thr_act->machine.pcb->iss.eip;
 415                *fp = (struct i386_frame *) thr_act->machine.pcb->iss.ebp;
 416                break;
 417            }
 418            /* falling down for unknown case */
 419        default:
 420        miss_frame:
 421            *ip = (db_addr_t)
 422                db_get_task_value((int)&(*fp)->f_retaddr, 4, FALSE, task);
 423            *lfp = *fp;
 424            *fp = (struct i386_frame *)
 425                db_get_task_value((int)&(*fp)->f_frame, 4, FALSE, task);
 426            break;
 427        }
 428}
 429
 430void
 431db_stack_trace_cmd(
 432        db_expr_t       addr,
 433        boolean_t       have_addr,
 434        db_expr_t       count,
 435        char            *modif)
 436{
 437        struct i386_frame *frame, *lastframe;
 438        int             *argp;
 439        db_addr_t       callpc, lastcallpc;
 440        int             frame_type;
 441        boolean_t       kernel_only = TRUE;
 442        boolean_t       trace_thread = FALSE;
 443        boolean_t       trace_all_threads = FALSE;
 444        int             thcount = 0;
 445        char            *filename;
 446        int             linenum;
 447        task_t          task;
 448        thread_t        th, top_act;
 449        int             user_frame;
 450        int             frame_count;
 451        jmp_buf_t       *prev;
 452        jmp_buf_t       db_jmp_buf;
 453        queue_entry_t   act_list;
 454
 455        if (!db_trace_symbols_found)
 456            db_find_trace_symbols();
 457
 458        {
 459            register char *cp = modif;
 460            register char c;
 461
 462            while ((c = *cp++) != 0) {
 463                if (c == 't')
 464                    trace_thread = TRUE;
 465                if (c == 'T') {
 466                    trace_all_threads = TRUE;
 467                    trace_thread = TRUE;
 468                }
 469                if (c == 'u')
 470                    kernel_only = FALSE;
 471            }
 472        }
 473
 474        if (trace_all_threads) {
 475            if (!have_addr && !trace_thread) {
 476                have_addr = TRUE;
 477                trace_thread = TRUE;
 478                act_list = &(current_task()->thr_acts);
 479                addr = (db_expr_t) queue_first(act_list);
 480            } else if (trace_thread) {
 481                if (have_addr) {
 482                    if (!db_check_act_address_valid((thread_t)addr)) {
 483                        if (db_lookup_task((task_t)addr) == -1)
 484                            return;
 485                        act_list = &(((task_t)addr)->thr_acts);
 486                        addr = (db_expr_t) queue_first(act_list);
 487                    } else {
 488                        act_list = &(((thread_t)addr)->task->thr_acts);
 489                        thcount = db_lookup_task_act(((thread_t)addr)->task,
 490                                                        (thread_t)addr);
 491                    }
 492                } else {
 493                    th = db_default_act;
 494                    if (th == THREAD_NULL)
 495                        th = current_thread();
 496                    if (th == THREAD_NULL) {
 497                        db_printf("no active thr_act\n");
 498                        return;
 499                    }
 500                    have_addr = TRUE;
 501                    act_list = &th->task->thr_acts;
 502                    addr = (db_expr_t) queue_first(act_list);
 503                }
 504            }
 505        }
 506
 507        if (count == -1)
 508            count = 65535;
 509
 510    next_thread:
 511        top_act = THREAD_NULL;
 512
 513        user_frame = 0;
 514        frame_count = count;
 515
 516        if (!have_addr && !trace_thread) {
 517            frame = (struct i386_frame *)ddb_regs.ebp;
 518            callpc = (db_addr_t)ddb_regs.eip;
 519            th = current_thread();
 520            task = (th != THREAD_NULL)? th->task: TASK_NULL;
 521        } else if (trace_thread) {
 522            if (have_addr) {
 523                th = (thread_t) addr;
 524                if (!db_check_act_address_valid(th))
 525                    return;
 526            } else {
 527                th = db_default_act;
 528                if (th == THREAD_NULL)
 529                   th = current_thread();
 530                if (th == THREAD_NULL) {
 531                   db_printf("no active thread\n");
 532                   return;
 533                }
 534            }
 535            if (trace_all_threads)
 536                db_printf("---------- Thread 0x%x (#%d of %d) ----------\n",
 537                      addr, thcount, th->task->thr_act_count);
 538
 539        next_activation:
 540            user_frame = 0;
 541
 542            task = th->task;
 543            if (th == current_thread()) {
 544                frame = (struct i386_frame *)ddb_regs.ebp;
 545                callpc = (db_addr_t)ddb_regs.eip;
 546            } else {
 547                if (th->machine.pcb == 0) {
 548                    db_printf("thread has no pcb\n");
 549                    return;
 550                }
 551                if (!th->thread) {
 552                    register struct i386_saved_state *iss =
 553                                                &th->machine.pcb->iss;
 554
 555                    db_printf("thread has no shuttle\n");
 556#if 0
 557                    frame = (struct i386_frame *) (iss->ebp);
 558                    callpc = (db_addr_t) (iss->eip);
 559#else
 560                    goto thread_done;
 561#endif
 562                }
 563                else if ((th->thread->state & TH_STACK_HANDOFF) ||
 564                          th->thread->kernel_stack == 0) {
 565                    register struct i386_saved_state *iss =
 566                                                &th->machine.pcb->iss;
 567
 568                    db_printf("Continuation ");
 569                    db_task_printsym((db_expr_t)th->thread->continuation,
 570                                                        DB_STGY_PROC, task);
 571                    db_printf("\n");
 572                    frame = (struct i386_frame *) (iss->ebp);
 573                    callpc = (db_addr_t) (iss->eip);
 574                } else {
 575                    int cpu;
 576
 577                    for (cpu = 0; cpu < real_ncpus; cpu++) {
 578                        if (cpu_datap(cpu)->cpu_running == TRUE &&
 579                            cpu_datap(cpu)->cpu_active_thread == th->thread &&
 580                            saved_state[cpu]) {
 581                            break;
 582                        }
 583                    }
 584                    if (top_act != THREAD_NULL) {
 585                            /*
 586                             * Trying to get the backtrace of an activation
 587                             * which is not the top_most one in the RPC chain:
 588                             * use the activation's pcb.
 589                             */
 590                            register struct i386_saved_state *iss =
 591                                &th->machine.pcb->iss;
 592                            frame = (struct i386_frame *) (iss->ebp);
 593                            callpc = (db_addr_t) (iss->eip);
 594                    } else {
 595                        if (cpu == NCPUS) {
 596                            register struct i386_kernel_state *iks;
 597                            int r;
 598
 599                            iks = STACK_IKS(th->thread->kernel_stack);
 600                            prev = db_recover;
 601                            if ((r = _setjmp(db_recover = &db_jmp_buf)) == 0) {
 602                                frame = (struct i386_frame *) (iks->k_ebp);
 603                                callpc = (db_addr_t) (iks->k_eip);
 604                            } else {
 605                                /*
 606                                 * The kernel stack has probably been
 607                                 * paged out (swapped out activation).
 608                                 */
 609                                db_recover = prev;
 610                                if (r == 2)     /* 'q' from db_more() */
 611                                    db_error(0);
 612                                db_printf("<kernel stack (0x%x) error "
 613                                          "(probably swapped out)>\n",
 614                                          iks);
 615                                goto thread_done;
 616                            }
 617                            db_recover = prev;
 618                        } else {
 619                            db_printf(">>>>> active on cpu %d <<<<<\n",
 620                                      cpu);
 621                            frame = (struct i386_frame *)
 622                                saved_state[cpu]->ebp;
 623                            callpc = (db_addr_t) saved_state[cpu]->eip;
 624                        }
 625                    }
 626                }
 627            }
 628        } else {
 629            frame = (struct i386_frame *)addr;
 630            th = (db_default_act)? db_default_act: current_thread();
 631            task = (th != THREAD_NULL)? th->task: TASK_NULL;
 632            callpc = (db_addr_t)db_get_task_value((int)&frame->f_retaddr,
 633                                                  4, 
 634                                                  FALSE, 
 635                                                  (user_frame) ? task : 0);
 636        }
 637
 638        if (!INKERNELSTACK((unsigned)frame, th)) {
 639            db_printf(">>>>> user space <<<<<\n");
 640            if (kernel_only)
 641                goto thread_done;
 642            user_frame++;
 643        } else if (INKSERVER(callpc) && INKSERVER(frame)) {
 644            db_printf(">>>>> INKserver space <<<<<\n");
 645        }
 646
 647        lastframe = 0;
 648        lastcallpc = (db_addr_t) 0;
 649        while (frame_count-- && frame != 0) {
 650            int narg;
 651            char *      name;
 652            db_expr_t   offset;
 653            db_addr_t call_func = 0;
 654            int r;
 655
 656            db_symbol_values(NULL,
 657                             db_search_task_symbol_and_line(
 658                                        callpc,
 659                                        DB_STGY_XTRN, 
 660                                        &offset,
 661                                        &filename,
 662                                        &linenum,
 663                                        (user_frame) ? task : 0,
 664                                        &narg),
 665                             &name, (db_expr_t *)&call_func);
 666            if (user_frame == 0) {
 667                if (call_func == db_user_trap_symbol_value ||
 668                    call_func == db_kernel_trap_symbol_value) {
 669                    frame_type = TRAP;
 670                    narg = 1;
 671                } else if (call_func == db_interrupt_symbol_value) {
 672                    frame_type = INTERRUPT;
 673                    goto next_frame;
 674                } else if (call_func == db_syscall_symbol_value) {
 675                    frame_type = SYSCALL;
 676                    goto next_frame;
 677                } else {
 678                    frame_type = 0;
 679                    prev = db_recover;
 680                    if ((r = _setjmp(db_recover = &db_jmp_buf)) == 0) {
 681                        if (narg < 0)
 682                            narg = db_numargs(frame,
 683                                              (user_frame) ? task : 0);
 684                        db_recover = prev;
 685                    } else {
 686                        db_recover = prev;
 687                        goto thread_done;
 688                    }
 689                }
 690            } else {
 691                frame_type = 0;
 692                prev = db_recover;
 693                if ((r = _setjmp(db_recover = &db_jmp_buf)) == 0) {
 694                    if (narg < 0)
 695                        narg = db_numargs(frame,
 696                                          (user_frame) ? task : 0);
 697                    db_recover = prev;
 698                } else {
 699                    db_recover = prev;
 700                    goto thread_done;
 701                }
 702            }
 703
 704            if (name == 0 || offset > db_maxoff) {
 705                db_printf("0x%x 0x%x(", frame, callpc);
 706                offset = 0;
 707            } else
 708                db_printf("0x%x %s(", frame, name);
 709
 710            argp = &frame->f_arg0;
 711            while (narg > 0) {
 712                int value;
 713
 714                prev = db_recover;
 715                if ((r = _setjmp(db_recover = &db_jmp_buf)) == 0) {
 716                    value = db_get_task_value((int)argp,
 717                                              4,
 718                                              FALSE,
 719                                              (user_frame) ? task : 0);
 720                } else {
 721                    db_recover = prev;
 722                    if (r == 2)         /* 'q' from db_more() */
 723                        db_error(0);
 724                    db_printf("... <stack error>)");
 725                    if (offset)
 726                        db_printf("+%x", offset);
 727                    if (filename) {
 728                        db_printf(" [%s", filename);
 729                        if (linenum > 0)
 730                            db_printf(":%d", linenum);
 731                        db_printf("]");
 732                    }
 733                    db_printf("\n");
 734                    goto thread_done;
 735                }
 736                db_recover = prev;
 737                db_printf("%x", value);
 738                argp++;
 739                if (--narg != 0)
 740                    db_printf(",");
 741            }
 742            if (narg < 0)
 743                db_printf("...");
 744            db_printf(")");
 745            if (offset) {
 746                db_printf("+%x", offset);
 747            }
 748            if (filename) {
 749                db_printf(" [%s", filename);
 750                if (linenum > 0)
 751                    db_printf(":%d", linenum);
 752                db_printf("]");
 753            }
 754            db_printf("\n");
 755
 756        next_frame:
 757            lastcallpc = callpc;
 758            db_nextframe(&lastframe, &frame, &callpc, frame_type,
 759                         (user_frame) ? th : THREAD_NULL);
 760
 761            if (frame == 0) {
 762                if (th->lower != THREAD_NULL) {
 763                    if (top_act == THREAD_NULL)
 764                        top_act = th;
 765                    th = th->lower;
 766                    db_printf(">>>>> next activation 0x%x ($task%d.%d) <<<<<\n",
 767                              th,
 768                              db_lookup_task(th->task),
 769                              db_lookup_task_act(th->task, th));
 770                    goto next_activation;
 771                }
 772                /* end of chain */
 773                break;
 774            }
 775            if (!INKERNELSTACK(lastframe, th) ||
 776                !INKERNELSTACK((unsigned)frame, th))
 777                user_frame++;
 778            if (user_frame == 1) {
 779                db_printf(">>>>> user space <<<<<\n");
 780                if (kernel_only)
 781                    break;
 782            } else if ((!INKSERVER(lastframe) || !INKSERVER(lastcallpc)) &&
 783                        (INKSERVER(callpc) && INKSERVER(frame))) {
 784                db_printf(">>>>> inkserver space <<<<<\n");
 785            }
 786            if (frame <= lastframe) {
 787                if ((INKERNELSTACK(lastframe, th) &&
 788                     !INKERNELSTACK(frame, th)) ||
 789                    (INKSERVER(lastframe) ^ INKSERVER(frame)))
 790                    continue;
 791                db_printf("Bad frame pointer: 0x%x\n", frame);
 792                break;
 793            }
 794        }
 795
 796    thread_done:
 797        if (trace_all_threads) {
 798            if (top_act != THREAD_NULL)
 799                th = top_act;
 800            th = (thread_t) queue_next(&th->thr_acts);
 801            if (! queue_end(act_list, (queue_entry_t) th)) {
 802                db_printf("\n");
 803                addr = (db_expr_t) th;
 804                thcount++;
 805                goto next_thread;
 806
 807            }
 808        }
 809}
 810
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.