1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate #define _SYSCALL32 30*7c478bd9Sstevel@tonic-gate 31*7c478bd9Sstevel@tonic-gate #include <stdio.h> 32*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 33*7c478bd9Sstevel@tonic-gate #include <unistd.h> 34*7c478bd9Sstevel@tonic-gate #include <ctype.h> 35*7c478bd9Sstevel@tonic-gate #include <string.h> 36*7c478bd9Sstevel@tonic-gate #include <memory.h> 37*7c478bd9Sstevel@tonic-gate #include <errno.h> 38*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 39*7c478bd9Sstevel@tonic-gate #include <sys/stack.h> 40*7c478bd9Sstevel@tonic-gate #include <signal.h> 41*7c478bd9Sstevel@tonic-gate #include <limits.h> 42*7c478bd9Sstevel@tonic-gate #include <sys/isa_defs.h> 43*7c478bd9Sstevel@tonic-gate #include <proc_service.h> 44*7c478bd9Sstevel@tonic-gate #include <dlfcn.h> 45*7c478bd9Sstevel@tonic-gate #include <fnmatch.h> 46*7c478bd9Sstevel@tonic-gate #include <libproc.h> 47*7c478bd9Sstevel@tonic-gate #include "ramdata.h" 48*7c478bd9Sstevel@tonic-gate #include "systable.h" 49*7c478bd9Sstevel@tonic-gate #include "print.h" 50*7c478bd9Sstevel@tonic-gate #include "proto.h" 51*7c478bd9Sstevel@tonic-gate #include "htbl.h" 52*7c478bd9Sstevel@tonic-gate 53*7c478bd9Sstevel@tonic-gate /* 54*7c478bd9Sstevel@tonic-gate * Functions supporting library function call tracing. 55*7c478bd9Sstevel@tonic-gate */ 56*7c478bd9Sstevel@tonic-gate 57*7c478bd9Sstevel@tonic-gate typedef struct { 58*7c478bd9Sstevel@tonic-gate prmap_t *pmap; 59*7c478bd9Sstevel@tonic-gate int nmap; 60*7c478bd9Sstevel@tonic-gate } ph_map_t; 61*7c478bd9Sstevel@tonic-gate 62*7c478bd9Sstevel@tonic-gate /* 63*7c478bd9Sstevel@tonic-gate * static functions in this file. 64*7c478bd9Sstevel@tonic-gate */ 65*7c478bd9Sstevel@tonic-gate void function_entry(private_t *, struct bkpt *, struct callstack *); 66*7c478bd9Sstevel@tonic-gate void function_return(private_t *, struct callstack *); 67*7c478bd9Sstevel@tonic-gate int object_iter(void *, const prmap_t *, const char *); 68*7c478bd9Sstevel@tonic-gate int symbol_iter(void *, const GElf_Sym *, const char *); 69*7c478bd9Sstevel@tonic-gate uintptr_t get_return_address(uintptr_t *); 70*7c478bd9Sstevel@tonic-gate int get_arguments(long *argp); 71*7c478bd9Sstevel@tonic-gate uintptr_t previous_fp(uintptr_t, uintptr_t *); 72*7c478bd9Sstevel@tonic-gate int lwp_stack_traps(void *cd, const lwpstatus_t *Lsp); 73*7c478bd9Sstevel@tonic-gate int thr_stack_traps(const td_thrhandle_t *Thp, void *cd); 74*7c478bd9Sstevel@tonic-gate struct bkpt *create_bkpt(uintptr_t, int, int); 75*7c478bd9Sstevel@tonic-gate void set_deferred_breakpoints(void); 76*7c478bd9Sstevel@tonic-gate 77*7c478bd9Sstevel@tonic-gate #define DEF_MAXCALL 16 /* initial value of Stk->maxcall */ 78*7c478bd9Sstevel@tonic-gate 79*7c478bd9Sstevel@tonic-gate #define FAULT_ADDR ((uintptr_t)(0-8)) 80*7c478bd9Sstevel@tonic-gate 81*7c478bd9Sstevel@tonic-gate #define HASHSZ 2048 82*7c478bd9Sstevel@tonic-gate #define bpt_hash(addr) ((((addr) >> 13) ^ ((addr) >> 2)) & 0x7ff) 83*7c478bd9Sstevel@tonic-gate 84*7c478bd9Sstevel@tonic-gate static void 85*7c478bd9Sstevel@tonic-gate setup_thread_agent(void) 86*7c478bd9Sstevel@tonic-gate { 87*7c478bd9Sstevel@tonic-gate struct bkpt *Bp; 88*7c478bd9Sstevel@tonic-gate td_notify_t notify; 89*7c478bd9Sstevel@tonic-gate td_thr_events_t events; 90*7c478bd9Sstevel@tonic-gate 91*7c478bd9Sstevel@tonic-gate if (Thr_agent != NULL) /* only once */ 92*7c478bd9Sstevel@tonic-gate return; 93*7c478bd9Sstevel@tonic-gate if (td_init() != TD_OK || td_ta_new(Proc, &Thr_agent) != TD_OK) 94*7c478bd9Sstevel@tonic-gate Thr_agent = NULL; 95*7c478bd9Sstevel@tonic-gate else { 96*7c478bd9Sstevel@tonic-gate td_event_emptyset(&events); 97*7c478bd9Sstevel@tonic-gate td_event_addset(&events, TD_CREATE); 98*7c478bd9Sstevel@tonic-gate if (td_ta_event_addr(Thr_agent, TD_CREATE, ¬ify) == TD_OK && 99*7c478bd9Sstevel@tonic-gate notify.type == NOTIFY_BPT && 100*7c478bd9Sstevel@tonic-gate td_ta_set_event(Thr_agent, &events) == TD_OK && 101*7c478bd9Sstevel@tonic-gate (Bp = create_bkpt(notify.u.bptaddr, 0, 1)) != NULL) 102*7c478bd9Sstevel@tonic-gate Bp->flags |= BPT_TD_CREATE; 103*7c478bd9Sstevel@tonic-gate } 104*7c478bd9Sstevel@tonic-gate } 105*7c478bd9Sstevel@tonic-gate 106*7c478bd9Sstevel@tonic-gate /* 107*7c478bd9Sstevel@tonic-gate * Establishment of breakpoints on traced library functions. 108*7c478bd9Sstevel@tonic-gate */ 109*7c478bd9Sstevel@tonic-gate void 110*7c478bd9Sstevel@tonic-gate establish_breakpoints(void) 111*7c478bd9Sstevel@tonic-gate { 112*7c478bd9Sstevel@tonic-gate if (Dynpat == NULL) 113*7c478bd9Sstevel@tonic-gate return; 114*7c478bd9Sstevel@tonic-gate 115*7c478bd9Sstevel@tonic-gate /* allocate the breakpoint hash table */ 116*7c478bd9Sstevel@tonic-gate if (bpt_hashtable == NULL) { 117*7c478bd9Sstevel@tonic-gate bpt_hashtable = my_malloc(HASHSZ * sizeof (struct bkpt *), 118*7c478bd9Sstevel@tonic-gate NULL); 119*7c478bd9Sstevel@tonic-gate (void) memset(bpt_hashtable, 0, 120*7c478bd9Sstevel@tonic-gate HASHSZ * sizeof (struct bkpt *)); 121*7c478bd9Sstevel@tonic-gate } 122*7c478bd9Sstevel@tonic-gate 123*7c478bd9Sstevel@tonic-gate /* 124*7c478bd9Sstevel@tonic-gate * Set special rtld_db event breakpoints, first time only. 125*7c478bd9Sstevel@tonic-gate */ 126*7c478bd9Sstevel@tonic-gate if (Rdb_agent == NULL && 127*7c478bd9Sstevel@tonic-gate (Rdb_agent = Prd_agent(Proc)) != NULL) { 128*7c478bd9Sstevel@tonic-gate rd_notify_t notify; 129*7c478bd9Sstevel@tonic-gate struct bkpt *Bp; 130*7c478bd9Sstevel@tonic-gate 131*7c478bd9Sstevel@tonic-gate (void) rd_event_enable(Rdb_agent, 1); 132*7c478bd9Sstevel@tonic-gate if (rd_event_addr(Rdb_agent, RD_PREINIT, ¬ify) == RD_OK && 133*7c478bd9Sstevel@tonic-gate (Bp = create_bkpt(notify.u.bptaddr, 0, 1)) != NULL) 134*7c478bd9Sstevel@tonic-gate Bp->flags |= BPT_PREINIT; 135*7c478bd9Sstevel@tonic-gate if (rd_event_addr(Rdb_agent, RD_POSTINIT, ¬ify) == RD_OK && 136*7c478bd9Sstevel@tonic-gate (Bp = create_bkpt(notify.u.bptaddr, 0, 1)) != NULL) 137*7c478bd9Sstevel@tonic-gate Bp->flags |= BPT_POSTINIT; 138*7c478bd9Sstevel@tonic-gate if (rd_event_addr(Rdb_agent, RD_DLACTIVITY, ¬ify) == RD_OK && 139*7c478bd9Sstevel@tonic-gate (Bp = create_bkpt(notify.u.bptaddr, 0, 1)) != NULL) 140*7c478bd9Sstevel@tonic-gate Bp->flags |= BPT_DLACTIVITY; 141*7c478bd9Sstevel@tonic-gate } 142*7c478bd9Sstevel@tonic-gate 143*7c478bd9Sstevel@tonic-gate /* 144*7c478bd9Sstevel@tonic-gate * Set special thread event breakpoint, first time libc is seen. 145*7c478bd9Sstevel@tonic-gate */ 146*7c478bd9Sstevel@tonic-gate if (Thr_agent == NULL) 147*7c478bd9Sstevel@tonic-gate setup_thread_agent(); 148*7c478bd9Sstevel@tonic-gate 149*7c478bd9Sstevel@tonic-gate /* 150*7c478bd9Sstevel@tonic-gate * Tell libproc to update its mappings. 151*7c478bd9Sstevel@tonic-gate */ 152*7c478bd9Sstevel@tonic-gate Pupdate_maps(Proc); 153*7c478bd9Sstevel@tonic-gate 154*7c478bd9Sstevel@tonic-gate /* 155*7c478bd9Sstevel@tonic-gate * Iterate over the shared objects, creating breakpoints. 156*7c478bd9Sstevel@tonic-gate */ 157*7c478bd9Sstevel@tonic-gate (void) Pobject_iter(Proc, object_iter, NULL); 158*7c478bd9Sstevel@tonic-gate 159*7c478bd9Sstevel@tonic-gate /* 160*7c478bd9Sstevel@tonic-gate * Now actually set all the breakpoints we just created. 161*7c478bd9Sstevel@tonic-gate */ 162*7c478bd9Sstevel@tonic-gate set_deferred_breakpoints(); 163*7c478bd9Sstevel@tonic-gate } 164*7c478bd9Sstevel@tonic-gate 165*7c478bd9Sstevel@tonic-gate /* 166*7c478bd9Sstevel@tonic-gate * Initial establishment of stacks in a newly-grabbed process. 167*7c478bd9Sstevel@tonic-gate * establish_breakpoints() has already been called. 168*7c478bd9Sstevel@tonic-gate */ 169*7c478bd9Sstevel@tonic-gate void 170*7c478bd9Sstevel@tonic-gate establish_stacks(void) 171*7c478bd9Sstevel@tonic-gate { 172*7c478bd9Sstevel@tonic-gate const pstatus_t *Psp = Pstatus(Proc); 173*7c478bd9Sstevel@tonic-gate char mapfile[64]; 174*7c478bd9Sstevel@tonic-gate int mapfd; 175*7c478bd9Sstevel@tonic-gate struct stat statb; 176*7c478bd9Sstevel@tonic-gate prmap_t *Pmap = NULL; 177*7c478bd9Sstevel@tonic-gate int nmap = 0; 178*7c478bd9Sstevel@tonic-gate ph_map_t ph_map; 179*7c478bd9Sstevel@tonic-gate 180*7c478bd9Sstevel@tonic-gate (void) sprintf(mapfile, "/proc/%d/rmap", (int)Psp->pr_pid); 181*7c478bd9Sstevel@tonic-gate if ((mapfd = open(mapfile, O_RDONLY)) < 0 || 182*7c478bd9Sstevel@tonic-gate fstat(mapfd, &statb) != 0 || 183*7c478bd9Sstevel@tonic-gate statb.st_size < sizeof (prmap_t) || 184*7c478bd9Sstevel@tonic-gate (Pmap = my_malloc(statb.st_size, NULL)) == NULL || 185*7c478bd9Sstevel@tonic-gate (nmap = pread(mapfd, Pmap, statb.st_size, 0L)) <= 0 || 186*7c478bd9Sstevel@tonic-gate (nmap /= sizeof (prmap_t)) == 0) { 187*7c478bd9Sstevel@tonic-gate if (Pmap != NULL) 188*7c478bd9Sstevel@tonic-gate free(Pmap); 189*7c478bd9Sstevel@tonic-gate Pmap = NULL; 190*7c478bd9Sstevel@tonic-gate nmap = 0; 191*7c478bd9Sstevel@tonic-gate } 192*7c478bd9Sstevel@tonic-gate if (mapfd >= 0) 193*7c478bd9Sstevel@tonic-gate (void) close(mapfd); 194*7c478bd9Sstevel@tonic-gate 195*7c478bd9Sstevel@tonic-gate /* 196*7c478bd9Sstevel@tonic-gate * Iterate over lwps, establishing stacks. 197*7c478bd9Sstevel@tonic-gate */ 198*7c478bd9Sstevel@tonic-gate ph_map.pmap = Pmap; 199*7c478bd9Sstevel@tonic-gate ph_map.nmap = nmap; 200*7c478bd9Sstevel@tonic-gate (void) Plwp_iter(Proc, lwp_stack_traps, &ph_map); 201*7c478bd9Sstevel@tonic-gate if (Pmap != NULL) 202*7c478bd9Sstevel@tonic-gate free(Pmap); 203*7c478bd9Sstevel@tonic-gate 204*7c478bd9Sstevel@tonic-gate if (Thr_agent == NULL) 205*7c478bd9Sstevel@tonic-gate return; 206*7c478bd9Sstevel@tonic-gate 207*7c478bd9Sstevel@tonic-gate /* 208*7c478bd9Sstevel@tonic-gate * Iterate over unbound threads, establishing stacks. 209*7c478bd9Sstevel@tonic-gate */ 210*7c478bd9Sstevel@tonic-gate (void) td_ta_thr_iter(Thr_agent, thr_stack_traps, NULL, 211*7c478bd9Sstevel@tonic-gate TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY, 212*7c478bd9Sstevel@tonic-gate TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS); 213*7c478bd9Sstevel@tonic-gate } 214*7c478bd9Sstevel@tonic-gate 215*7c478bd9Sstevel@tonic-gate void 216*7c478bd9Sstevel@tonic-gate do_symbol_iter(const char *object_name, struct dynpat *Dyp) 217*7c478bd9Sstevel@tonic-gate { 218*7c478bd9Sstevel@tonic-gate if (*Dyp->Dp->prt_name == '\0') 219*7c478bd9Sstevel@tonic-gate object_name = PR_OBJ_EXEC; 220*7c478bd9Sstevel@tonic-gate 221*7c478bd9Sstevel@tonic-gate /* 222*7c478bd9Sstevel@tonic-gate * Always search the dynamic symbol table. 223*7c478bd9Sstevel@tonic-gate */ 224*7c478bd9Sstevel@tonic-gate (void) Psymbol_iter(Proc, object_name, 225*7c478bd9Sstevel@tonic-gate PR_DYNSYM, BIND_WEAK|BIND_GLOBAL|TYPE_FUNC, 226*7c478bd9Sstevel@tonic-gate symbol_iter, Dyp); 227*7c478bd9Sstevel@tonic-gate 228*7c478bd9Sstevel@tonic-gate /* 229*7c478bd9Sstevel@tonic-gate * Search the static symbol table if this is the 230*7c478bd9Sstevel@tonic-gate * executable file or if we are being asked to 231*7c478bd9Sstevel@tonic-gate * report internal calls within the library. 232*7c478bd9Sstevel@tonic-gate */ 233*7c478bd9Sstevel@tonic-gate if (object_name == PR_OBJ_EXEC || Dyp->internal) 234*7c478bd9Sstevel@tonic-gate (void) Psymbol_iter(Proc, object_name, 235*7c478bd9Sstevel@tonic-gate PR_SYMTAB, BIND_ANY|TYPE_FUNC, 236*7c478bd9Sstevel@tonic-gate symbol_iter, Dyp); 237*7c478bd9Sstevel@tonic-gate } 238*7c478bd9Sstevel@tonic-gate 239*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 240*7c478bd9Sstevel@tonic-gate int 241*7c478bd9Sstevel@tonic-gate object_iter(void *cd, const prmap_t *pmp, const char *object_name) 242*7c478bd9Sstevel@tonic-gate { 243*7c478bd9Sstevel@tonic-gate char name[100]; 244*7c478bd9Sstevel@tonic-gate struct dynpat *Dyp; 245*7c478bd9Sstevel@tonic-gate struct dynlib *Dp; 246*7c478bd9Sstevel@tonic-gate const char *str; 247*7c478bd9Sstevel@tonic-gate char *s; 248*7c478bd9Sstevel@tonic-gate int i; 249*7c478bd9Sstevel@tonic-gate 250*7c478bd9Sstevel@tonic-gate if ((pmp->pr_mflags & MA_WRITE) || !(pmp->pr_mflags & MA_EXEC)) 251*7c478bd9Sstevel@tonic-gate return (0); 252*7c478bd9Sstevel@tonic-gate 253*7c478bd9Sstevel@tonic-gate /* 254*7c478bd9Sstevel@tonic-gate * Set special thread event breakpoint, first time libc is seen. 255*7c478bd9Sstevel@tonic-gate */ 256*7c478bd9Sstevel@tonic-gate if (Thr_agent == NULL && strstr(object_name, "/libc.so.") != NULL) 257*7c478bd9Sstevel@tonic-gate setup_thread_agent(); 258*7c478bd9Sstevel@tonic-gate 259*7c478bd9Sstevel@tonic-gate for (Dp = Dyn; Dp != NULL; Dp = Dp->next) 260*7c478bd9Sstevel@tonic-gate if (strcmp(object_name, Dp->lib_name) == 0 || 261*7c478bd9Sstevel@tonic-gate (strcmp(Dp->lib_name, "a.out") == 0 && 262*7c478bd9Sstevel@tonic-gate strcmp(pmp->pr_mapname, "a.out") == 0)) 263*7c478bd9Sstevel@tonic-gate break; 264*7c478bd9Sstevel@tonic-gate 265*7c478bd9Sstevel@tonic-gate if (Dp == NULL) { 266*7c478bd9Sstevel@tonic-gate Dp = my_malloc(sizeof (struct dynlib), NULL); 267*7c478bd9Sstevel@tonic-gate (void) memset(Dp, 0, sizeof (struct dynlib)); 268*7c478bd9Sstevel@tonic-gate if (strcmp(pmp->pr_mapname, "a.out") == 0) { 269*7c478bd9Sstevel@tonic-gate Dp->lib_name = strdup(pmp->pr_mapname); 270*7c478bd9Sstevel@tonic-gate Dp->match_name = strdup(pmp->pr_mapname); 271*7c478bd9Sstevel@tonic-gate Dp->prt_name = strdup(""); 272*7c478bd9Sstevel@tonic-gate } else { 273*7c478bd9Sstevel@tonic-gate Dp->lib_name = strdup(object_name); 274*7c478bd9Sstevel@tonic-gate if ((str = strrchr(object_name, '/')) != NULL) 275*7c478bd9Sstevel@tonic-gate str++; 276*7c478bd9Sstevel@tonic-gate else 277*7c478bd9Sstevel@tonic-gate str = object_name; 278*7c478bd9Sstevel@tonic-gate (void) strncpy(name, str, sizeof (name) - 2); 279*7c478bd9Sstevel@tonic-gate name[sizeof (name) - 2] = '\0'; 280*7c478bd9Sstevel@tonic-gate if ((s = strstr(name, ".so")) != NULL) 281*7c478bd9Sstevel@tonic-gate *s = '\0'; 282*7c478bd9Sstevel@tonic-gate Dp->match_name = strdup(name); 283*7c478bd9Sstevel@tonic-gate (void) strcat(name, ":"); 284*7c478bd9Sstevel@tonic-gate Dp->prt_name = strdup(name); 285*7c478bd9Sstevel@tonic-gate } 286*7c478bd9Sstevel@tonic-gate Dp->next = Dyn; 287*7c478bd9Sstevel@tonic-gate Dyn = Dp; 288*7c478bd9Sstevel@tonic-gate } 289*7c478bd9Sstevel@tonic-gate 290*7c478bd9Sstevel@tonic-gate if (Dp->built || 291*7c478bd9Sstevel@tonic-gate (not_consist && strcmp(Dp->prt_name, "ld:") != 0)) /* kludge */ 292*7c478bd9Sstevel@tonic-gate return (0); 293*7c478bd9Sstevel@tonic-gate 294*7c478bd9Sstevel@tonic-gate if (hflag && not_consist) 295*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "not_consist is TRUE, building %s\n", 296*7c478bd9Sstevel@tonic-gate Dp->lib_name); 297*7c478bd9Sstevel@tonic-gate 298*7c478bd9Sstevel@tonic-gate Dp->base = pmp->pr_vaddr; 299*7c478bd9Sstevel@tonic-gate Dp->size = pmp->pr_size; 300*7c478bd9Sstevel@tonic-gate 301*7c478bd9Sstevel@tonic-gate /* 302*7c478bd9Sstevel@tonic-gate * For every dynlib pattern that matches this library's name, 303*7c478bd9Sstevel@tonic-gate * iterate through all of the library's symbols looking for 304*7c478bd9Sstevel@tonic-gate * matching symbol name patterns. 305*7c478bd9Sstevel@tonic-gate */ 306*7c478bd9Sstevel@tonic-gate for (Dyp = Dynpat; Dyp != NULL; Dyp = Dyp->next) { 307*7c478bd9Sstevel@tonic-gate if (interrupt|sigusr1) 308*7c478bd9Sstevel@tonic-gate break; 309*7c478bd9Sstevel@tonic-gate for (i = 0; i < Dyp->nlibpat; i++) { 310*7c478bd9Sstevel@tonic-gate if (interrupt|sigusr1) 311*7c478bd9Sstevel@tonic-gate break; 312*7c478bd9Sstevel@tonic-gate if (fnmatch(Dyp->libpat[i], Dp->match_name, 0) != 0) 313*7c478bd9Sstevel@tonic-gate continue; /* no match */ 314*7c478bd9Sstevel@tonic-gate 315*7c478bd9Sstevel@tonic-gate /* 316*7c478bd9Sstevel@tonic-gate * Require an exact match for the executable (a.out) 317*7c478bd9Sstevel@tonic-gate * and for the dynamic linker (ld.so.1). 318*7c478bd9Sstevel@tonic-gate */ 319*7c478bd9Sstevel@tonic-gate if ((strcmp(Dp->match_name, "a.out") == 0 || 320*7c478bd9Sstevel@tonic-gate strcmp(Dp->match_name, "ld") == 0) && 321*7c478bd9Sstevel@tonic-gate strcmp(Dyp->libpat[i], Dp->match_name) != 0) 322*7c478bd9Sstevel@tonic-gate continue; 323*7c478bd9Sstevel@tonic-gate 324*7c478bd9Sstevel@tonic-gate /* 325*7c478bd9Sstevel@tonic-gate * Set Dyp->Dp to Dp so symbol_iter() can use it. 326*7c478bd9Sstevel@tonic-gate */ 327*7c478bd9Sstevel@tonic-gate Dyp->Dp = Dp; 328*7c478bd9Sstevel@tonic-gate do_symbol_iter(object_name, Dyp); 329*7c478bd9Sstevel@tonic-gate Dyp->Dp = NULL; 330*7c478bd9Sstevel@tonic-gate } 331*7c478bd9Sstevel@tonic-gate } 332*7c478bd9Sstevel@tonic-gate 333*7c478bd9Sstevel@tonic-gate Dp->built = TRUE; 334*7c478bd9Sstevel@tonic-gate return (interrupt | sigusr1); 335*7c478bd9Sstevel@tonic-gate } 336*7c478bd9Sstevel@tonic-gate 337*7c478bd9Sstevel@tonic-gate /* 338*7c478bd9Sstevel@tonic-gate * Search for an existing breakpoint at the 'pc' location. 339*7c478bd9Sstevel@tonic-gate */ 340*7c478bd9Sstevel@tonic-gate struct bkpt * 341*7c478bd9Sstevel@tonic-gate get_bkpt(uintptr_t pc) 342*7c478bd9Sstevel@tonic-gate { 343*7c478bd9Sstevel@tonic-gate struct bkpt *Bp; 344*7c478bd9Sstevel@tonic-gate 345*7c478bd9Sstevel@tonic-gate for (Bp = bpt_hashtable[bpt_hash(pc)]; Bp != NULL; Bp = Bp->next) 346*7c478bd9Sstevel@tonic-gate if (pc == Bp->addr) 347*7c478bd9Sstevel@tonic-gate break; 348*7c478bd9Sstevel@tonic-gate 349*7c478bd9Sstevel@tonic-gate return (Bp); 350*7c478bd9Sstevel@tonic-gate } 351*7c478bd9Sstevel@tonic-gate 352*7c478bd9Sstevel@tonic-gate /* 353*7c478bd9Sstevel@tonic-gate * Create a breakpoint at 'pc', if one is not there already. 354*7c478bd9Sstevel@tonic-gate * 'ret' is true when creating a function return breakpoint, in which case 355*7c478bd9Sstevel@tonic-gate * fail and return NULL if the breakpoint would be created in writeable data. 356*7c478bd9Sstevel@tonic-gate * If 'set' it true, set the breakpoint in the process now. 357*7c478bd9Sstevel@tonic-gate */ 358*7c478bd9Sstevel@tonic-gate struct bkpt * 359*7c478bd9Sstevel@tonic-gate create_bkpt(uintptr_t pc, int ret, int set) 360*7c478bd9Sstevel@tonic-gate { 361*7c478bd9Sstevel@tonic-gate uint_t hix = bpt_hash(pc); 362*7c478bd9Sstevel@tonic-gate struct bkpt *Bp; 363*7c478bd9Sstevel@tonic-gate const prmap_t *pmp; 364*7c478bd9Sstevel@tonic-gate 365*7c478bd9Sstevel@tonic-gate for (Bp = bpt_hashtable[hix]; Bp != NULL; Bp = Bp->next) 366*7c478bd9Sstevel@tonic-gate if (pc == Bp->addr) 367*7c478bd9Sstevel@tonic-gate return (Bp); 368*7c478bd9Sstevel@tonic-gate 369*7c478bd9Sstevel@tonic-gate /* 370*7c478bd9Sstevel@tonic-gate * Don't set return breakpoints on writeable data 371*7c478bd9Sstevel@tonic-gate * or on any space other than executable text. 372*7c478bd9Sstevel@tonic-gate * Don't set breakpoints in the child of a vfork() 373*7c478bd9Sstevel@tonic-gate * because that would modify the parent's address space. 374*7c478bd9Sstevel@tonic-gate */ 375*7c478bd9Sstevel@tonic-gate if (is_vfork_child || 376*7c478bd9Sstevel@tonic-gate (ret && 377*7c478bd9Sstevel@tonic-gate ((pmp = Paddr_to_text_map(Proc, pc)) == NULL || 378*7c478bd9Sstevel@tonic-gate !(pmp->pr_mflags & MA_EXEC) || 379*7c478bd9Sstevel@tonic-gate (pmp->pr_mflags & MA_WRITE)))) 380*7c478bd9Sstevel@tonic-gate return (NULL); 381*7c478bd9Sstevel@tonic-gate 382*7c478bd9Sstevel@tonic-gate /* create a new unnamed breakpoint */ 383*7c478bd9Sstevel@tonic-gate Bp = my_malloc(sizeof (struct bkpt), NULL); 384*7c478bd9Sstevel@tonic-gate Bp->sym_name = NULL; 385*7c478bd9Sstevel@tonic-gate Bp->dyn = NULL; 386*7c478bd9Sstevel@tonic-gate Bp->addr = pc; 387*7c478bd9Sstevel@tonic-gate Bp->instr = 0; 388*7c478bd9Sstevel@tonic-gate Bp->flags = 0; 389*7c478bd9Sstevel@tonic-gate if (set && Psetbkpt(Proc, Bp->addr, &Bp->instr) == 0) 390*7c478bd9Sstevel@tonic-gate Bp->flags |= BPT_ACTIVE; 391*7c478bd9Sstevel@tonic-gate Bp->next = bpt_hashtable[hix]; 392*7c478bd9Sstevel@tonic-gate bpt_hashtable[hix] = Bp; 393*7c478bd9Sstevel@tonic-gate 394*7c478bd9Sstevel@tonic-gate return (Bp); 395*7c478bd9Sstevel@tonic-gate } 396*7c478bd9Sstevel@tonic-gate 397*7c478bd9Sstevel@tonic-gate /* 398*7c478bd9Sstevel@tonic-gate * Set all breakpoints that haven't been set yet. 399*7c478bd9Sstevel@tonic-gate * Deactivate all breakpoints from modules that are not present any more. 400*7c478bd9Sstevel@tonic-gate */ 401*7c478bd9Sstevel@tonic-gate void 402*7c478bd9Sstevel@tonic-gate set_deferred_breakpoints(void) 403*7c478bd9Sstevel@tonic-gate { 404*7c478bd9Sstevel@tonic-gate struct bkpt *Bp; 405*7c478bd9Sstevel@tonic-gate int i; 406*7c478bd9Sstevel@tonic-gate 407*7c478bd9Sstevel@tonic-gate if (is_vfork_child) 408*7c478bd9Sstevel@tonic-gate return; 409*7c478bd9Sstevel@tonic-gate 410*7c478bd9Sstevel@tonic-gate for (i = 0; i < HASHSZ; i++) { 411*7c478bd9Sstevel@tonic-gate for (Bp = bpt_hashtable[i]; Bp != NULL; Bp = Bp->next) { 412*7c478bd9Sstevel@tonic-gate if (!(Bp->flags & BPT_ACTIVE)) { 413*7c478bd9Sstevel@tonic-gate if (!(Bp->flags & BPT_EXCLUDE) && 414*7c478bd9Sstevel@tonic-gate Psetbkpt(Proc, Bp->addr, &Bp->instr) == 0) 415*7c478bd9Sstevel@tonic-gate Bp->flags |= BPT_ACTIVE; 416*7c478bd9Sstevel@tonic-gate } else if (Paddr_to_text_map(Proc, Bp->addr) == NULL) { 417*7c478bd9Sstevel@tonic-gate Bp->flags &= ~BPT_ACTIVE; 418*7c478bd9Sstevel@tonic-gate } 419*7c478bd9Sstevel@tonic-gate } 420*7c478bd9Sstevel@tonic-gate } 421*7c478bd9Sstevel@tonic-gate } 422*7c478bd9Sstevel@tonic-gate 423*7c478bd9Sstevel@tonic-gate int 424*7c478bd9Sstevel@tonic-gate symbol_iter(void *cd, const GElf_Sym *sym, const char *sym_name) 425*7c478bd9Sstevel@tonic-gate { 426*7c478bd9Sstevel@tonic-gate struct dynpat *Dyp = cd; 427*7c478bd9Sstevel@tonic-gate struct dynlib *Dp = Dyp->Dp; 428*7c478bd9Sstevel@tonic-gate uintptr_t pc = sym->st_value; 429*7c478bd9Sstevel@tonic-gate struct bkpt *Bp; 430*7c478bd9Sstevel@tonic-gate int i; 431*7c478bd9Sstevel@tonic-gate 432*7c478bd9Sstevel@tonic-gate /* ignore any undefined symbols */ 433*7c478bd9Sstevel@tonic-gate if (sym->st_shndx == SHN_UNDEF) 434*7c478bd9Sstevel@tonic-gate return (0); 435*7c478bd9Sstevel@tonic-gate 436*7c478bd9Sstevel@tonic-gate /* 437*7c478bd9Sstevel@tonic-gate * Arbitrarily omit "_start" from the executable. 438*7c478bd9Sstevel@tonic-gate * (Avoid indentation before main().) 439*7c478bd9Sstevel@tonic-gate */ 440*7c478bd9Sstevel@tonic-gate if (*Dp->prt_name == '\0' && strcmp(sym_name, "_start") == 0) 441*7c478bd9Sstevel@tonic-gate return (0); 442*7c478bd9Sstevel@tonic-gate 443*7c478bd9Sstevel@tonic-gate /* 444*7c478bd9Sstevel@tonic-gate * Arbitrarily omit "_rt_boot" from the dynamic linker. 445*7c478bd9Sstevel@tonic-gate * (Avoid indentation before main().) 446*7c478bd9Sstevel@tonic-gate */ 447*7c478bd9Sstevel@tonic-gate if (strcmp(Dp->match_name, "ld") == 0 && 448*7c478bd9Sstevel@tonic-gate strcmp(sym_name, "_rt_boot") == 0) 449*7c478bd9Sstevel@tonic-gate return (0); 450*7c478bd9Sstevel@tonic-gate 451*7c478bd9Sstevel@tonic-gate /* 452*7c478bd9Sstevel@tonic-gate * Arbitrarily omit any symbols whose name starts with '.'. 453*7c478bd9Sstevel@tonic-gate * Apparantly putting a breakpoint on .umul causes a 454*7c478bd9Sstevel@tonic-gate * fatal error in libthread (%y is not restored correctly 455*7c478bd9Sstevel@tonic-gate * when a single step is taken). Looks like a /proc bug. 456*7c478bd9Sstevel@tonic-gate */ 457*7c478bd9Sstevel@tonic-gate if (*sym_name == '.') 458*7c478bd9Sstevel@tonic-gate return (0); 459*7c478bd9Sstevel@tonic-gate 460*7c478bd9Sstevel@tonic-gate /* 461*7c478bd9Sstevel@tonic-gate * For each pattern in the array of symbol patterns, 462*7c478bd9Sstevel@tonic-gate * if the pattern matches the symbol name, then 463*7c478bd9Sstevel@tonic-gate * create a breakpoint at the function in question. 464*7c478bd9Sstevel@tonic-gate */ 465*7c478bd9Sstevel@tonic-gate for (i = 0; i < Dyp->nsympat; i++) { 466*7c478bd9Sstevel@tonic-gate if (interrupt|sigusr1) 467*7c478bd9Sstevel@tonic-gate break; 468*7c478bd9Sstevel@tonic-gate if (fnmatch(Dyp->sympat[i], sym_name, 0) != 0) 469*7c478bd9Sstevel@tonic-gate continue; 470*7c478bd9Sstevel@tonic-gate 471*7c478bd9Sstevel@tonic-gate if ((Bp = create_bkpt(pc, 0, 0)) == NULL) /* can't fail */ 472*7c478bd9Sstevel@tonic-gate return (0); 473*7c478bd9Sstevel@tonic-gate 474*7c478bd9Sstevel@tonic-gate /* 475*7c478bd9Sstevel@tonic-gate * New breakpoints receive a name now. 476*7c478bd9Sstevel@tonic-gate * For existing breakpoints, prefer the subset name if possible, 477*7c478bd9Sstevel@tonic-gate * else prefer the shorter name. 478*7c478bd9Sstevel@tonic-gate */ 479*7c478bd9Sstevel@tonic-gate if (Bp->sym_name == NULL) { 480*7c478bd9Sstevel@tonic-gate Bp->sym_name = strdup(sym_name); 481*7c478bd9Sstevel@tonic-gate } else if (strstr(Bp->sym_name, sym_name) != NULL || 482*7c478bd9Sstevel@tonic-gate strlen(Bp->sym_name) > strlen(sym_name)) { 483*7c478bd9Sstevel@tonic-gate free(Bp->sym_name); 484*7c478bd9Sstevel@tonic-gate Bp->sym_name = strdup(sym_name); 485*7c478bd9Sstevel@tonic-gate } 486*7c478bd9Sstevel@tonic-gate Bp->dyn = Dp; 487*7c478bd9Sstevel@tonic-gate Bp->flags |= Dyp->flag; 488*7c478bd9Sstevel@tonic-gate if (Dyp->exclude) 489*7c478bd9Sstevel@tonic-gate Bp->flags |= BPT_EXCLUDE; 490*7c478bd9Sstevel@tonic-gate else if (Dyp->internal || *Dp->prt_name == '\0') 491*7c478bd9Sstevel@tonic-gate Bp->flags |= BPT_INTERNAL; 492*7c478bd9Sstevel@tonic-gate return (0); 493*7c478bd9Sstevel@tonic-gate } 494*7c478bd9Sstevel@tonic-gate 495*7c478bd9Sstevel@tonic-gate return (interrupt | sigusr1); 496*7c478bd9Sstevel@tonic-gate } 497*7c478bd9Sstevel@tonic-gate 498*7c478bd9Sstevel@tonic-gate /* For debugging only ---- */ 499*7c478bd9Sstevel@tonic-gate void 500*7c478bd9Sstevel@tonic-gate report_htable_stats(void) 501*7c478bd9Sstevel@tonic-gate { 502*7c478bd9Sstevel@tonic-gate const pstatus_t *Psp = Pstatus(Proc); 503*7c478bd9Sstevel@tonic-gate struct callstack *Stk; 504*7c478bd9Sstevel@tonic-gate struct bkpt *Bp; 505*7c478bd9Sstevel@tonic-gate uint_t Min = 1000000; 506*7c478bd9Sstevel@tonic-gate uint_t Max = 0; 507*7c478bd9Sstevel@tonic-gate uint_t Avg = 0; 508*7c478bd9Sstevel@tonic-gate uint_t Total = 0; 509*7c478bd9Sstevel@tonic-gate uint_t i, j; 510*7c478bd9Sstevel@tonic-gate uint_t bucket[HASHSZ]; 511*7c478bd9Sstevel@tonic-gate 512*7c478bd9Sstevel@tonic-gate if (Dynpat == NULL || !hflag) 513*7c478bd9Sstevel@tonic-gate return; 514*7c478bd9Sstevel@tonic-gate 515*7c478bd9Sstevel@tonic-gate hflag = FALSE; 516*7c478bd9Sstevel@tonic-gate (void) memset(bucket, 0, sizeof (bucket)); 517*7c478bd9Sstevel@tonic-gate 518*7c478bd9Sstevel@tonic-gate for (i = 0; i < HASHSZ; i++) { 519*7c478bd9Sstevel@tonic-gate j = 0; 520*7c478bd9Sstevel@tonic-gate for (Bp = bpt_hashtable[i]; Bp != NULL; Bp = Bp->next) 521*7c478bd9Sstevel@tonic-gate j++; 522*7c478bd9Sstevel@tonic-gate if (j < Min) 523*7c478bd9Sstevel@tonic-gate Min = j; 524*7c478bd9Sstevel@tonic-gate if (j > Max) 525*7c478bd9Sstevel@tonic-gate Max = j; 526*7c478bd9Sstevel@tonic-gate if (j < HASHSZ) 527*7c478bd9Sstevel@tonic-gate bucket[j]++; 528*7c478bd9Sstevel@tonic-gate Total += j; 529*7c478bd9Sstevel@tonic-gate } 530*7c478bd9Sstevel@tonic-gate Avg = (Total + HASHSZ / 2) / HASHSZ; 531*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "truss hash table statistics --------\n"); 532*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, " Total = %u\n", Total); 533*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, " Min = %u\n", Min); 534*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, " Max = %u\n", Max); 535*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, " Avg = %u\n", Avg); 536*7c478bd9Sstevel@tonic-gate for (i = 0; i < HASHSZ; i++) 537*7c478bd9Sstevel@tonic-gate if (bucket[i]) 538*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, " %3u buckets of size %d\n", 539*7c478bd9Sstevel@tonic-gate bucket[i], i); 540*7c478bd9Sstevel@tonic-gate 541*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "truss-detected stacks --------\n"); 542*7c478bd9Sstevel@tonic-gate for (Stk = callstack; Stk != NULL; Stk = Stk->next) { 543*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 544*7c478bd9Sstevel@tonic-gate " base = 0x%.8lx end = 0x%.8lx size = %ld\n", 545*7c478bd9Sstevel@tonic-gate (ulong_t)Stk->stkbase, 546*7c478bd9Sstevel@tonic-gate (ulong_t)Stk->stkend, 547*7c478bd9Sstevel@tonic-gate (ulong_t)(Stk->stkend - Stk->stkbase)); 548*7c478bd9Sstevel@tonic-gate } 549*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "primary unix stack --------\n"); 550*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 551*7c478bd9Sstevel@tonic-gate " base = 0x%.8lx end = 0x%.8lx size = %ld\n", 552*7c478bd9Sstevel@tonic-gate (ulong_t)Psp->pr_stkbase, 553*7c478bd9Sstevel@tonic-gate (ulong_t)(Psp->pr_stkbase + Psp->pr_stksize), 554*7c478bd9Sstevel@tonic-gate (ulong_t)Psp->pr_stksize); 555*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "nthr_create = %u\n", nthr_create); 556*7c478bd9Sstevel@tonic-gate } 557*7c478bd9Sstevel@tonic-gate 558*7c478bd9Sstevel@tonic-gate void 559*7c478bd9Sstevel@tonic-gate make_lwp_stack(const lwpstatus_t *Lsp, prmap_t *Pmap, int nmap) 560*7c478bd9Sstevel@tonic-gate { 561*7c478bd9Sstevel@tonic-gate const pstatus_t *Psp = Pstatus(Proc); 562*7c478bd9Sstevel@tonic-gate uintptr_t sp = Lsp->pr_reg[R_SP]; 563*7c478bd9Sstevel@tonic-gate id_t lwpid = Lsp->pr_lwpid; 564*7c478bd9Sstevel@tonic-gate struct callstack *Stk; 565*7c478bd9Sstevel@tonic-gate td_thrhandle_t th; 566*7c478bd9Sstevel@tonic-gate td_thrinfo_t thrinfo; 567*7c478bd9Sstevel@tonic-gate 568*7c478bd9Sstevel@tonic-gate if (data_model != PR_MODEL_LP64) 569*7c478bd9Sstevel@tonic-gate sp = (uint32_t)sp; 570*7c478bd9Sstevel@tonic-gate 571*7c478bd9Sstevel@tonic-gate /* check to see if we already have this stack */ 572*7c478bd9Sstevel@tonic-gate if (sp == 0) 573*7c478bd9Sstevel@tonic-gate return; 574*7c478bd9Sstevel@tonic-gate for (Stk = callstack; Stk != NULL; Stk = Stk->next) 575*7c478bd9Sstevel@tonic-gate if (sp >= Stk->stkbase && sp < Stk->stkend) 576*7c478bd9Sstevel@tonic-gate return; 577*7c478bd9Sstevel@tonic-gate 578*7c478bd9Sstevel@tonic-gate Stk = my_malloc(sizeof (struct callstack), NULL); 579*7c478bd9Sstevel@tonic-gate Stk->next = callstack; 580*7c478bd9Sstevel@tonic-gate callstack = Stk; 581*7c478bd9Sstevel@tonic-gate nstack++; 582*7c478bd9Sstevel@tonic-gate Stk->tref = 0; 583*7c478bd9Sstevel@tonic-gate Stk->tid = 0; 584*7c478bd9Sstevel@tonic-gate Stk->nthr_create = 0; 585*7c478bd9Sstevel@tonic-gate Stk->ncall = 0; 586*7c478bd9Sstevel@tonic-gate Stk->maxcall = DEF_MAXCALL; 587*7c478bd9Sstevel@tonic-gate Stk->stack = my_malloc(DEF_MAXCALL * sizeof (*Stk->stack), NULL); 588*7c478bd9Sstevel@tonic-gate 589*7c478bd9Sstevel@tonic-gate /* primary stack */ 590*7c478bd9Sstevel@tonic-gate if (sp >= Psp->pr_stkbase && sp < Psp->pr_stkbase + Psp->pr_stksize) { 591*7c478bd9Sstevel@tonic-gate Stk->stkbase = Psp->pr_stkbase; 592*7c478bd9Sstevel@tonic-gate Stk->stkend = Stk->stkbase + Psp->pr_stksize; 593*7c478bd9Sstevel@tonic-gate return; 594*7c478bd9Sstevel@tonic-gate } 595*7c478bd9Sstevel@tonic-gate 596*7c478bd9Sstevel@tonic-gate /* alternate stack */ 597*7c478bd9Sstevel@tonic-gate if ((Lsp->pr_altstack.ss_flags & SS_ONSTACK) && 598*7c478bd9Sstevel@tonic-gate sp >= (uintptr_t)Lsp->pr_altstack.ss_sp && 599*7c478bd9Sstevel@tonic-gate sp < (uintptr_t)Lsp->pr_altstack.ss_sp 600*7c478bd9Sstevel@tonic-gate + Lsp->pr_altstack.ss_size) { 601*7c478bd9Sstevel@tonic-gate Stk->stkbase = (uintptr_t)Lsp->pr_altstack.ss_sp; 602*7c478bd9Sstevel@tonic-gate Stk->stkend = Stk->stkbase + Lsp->pr_altstack.ss_size; 603*7c478bd9Sstevel@tonic-gate return; 604*7c478bd9Sstevel@tonic-gate } 605*7c478bd9Sstevel@tonic-gate 606*7c478bd9Sstevel@tonic-gate /* thread stacks? */ 607*7c478bd9Sstevel@tonic-gate if (Thr_agent != NULL && 608*7c478bd9Sstevel@tonic-gate td_ta_map_lwp2thr(Thr_agent, lwpid, &th) == TD_OK && 609*7c478bd9Sstevel@tonic-gate td_thr_get_info(&th, &thrinfo) == TD_OK && 610*7c478bd9Sstevel@tonic-gate sp >= (uintptr_t)thrinfo.ti_stkbase - thrinfo.ti_stksize && 611*7c478bd9Sstevel@tonic-gate sp < (uintptr_t)thrinfo.ti_stkbase) { 612*7c478bd9Sstevel@tonic-gate /* The bloody fools got this backwards! */ 613*7c478bd9Sstevel@tonic-gate Stk->stkend = (uintptr_t)thrinfo.ti_stkbase; 614*7c478bd9Sstevel@tonic-gate Stk->stkbase = Stk->stkend - thrinfo.ti_stksize; 615*7c478bd9Sstevel@tonic-gate return; 616*7c478bd9Sstevel@tonic-gate } 617*7c478bd9Sstevel@tonic-gate 618*7c478bd9Sstevel@tonic-gate /* last chance -- try the raw memory map */ 619*7c478bd9Sstevel@tonic-gate for (; nmap; nmap--, Pmap++) { 620*7c478bd9Sstevel@tonic-gate if (sp >= Pmap->pr_vaddr && 621*7c478bd9Sstevel@tonic-gate sp < Pmap->pr_vaddr + Pmap->pr_size) { 622*7c478bd9Sstevel@tonic-gate Stk->stkbase = Pmap->pr_vaddr; 623*7c478bd9Sstevel@tonic-gate Stk->stkend = Pmap->pr_vaddr + Pmap->pr_size; 624*7c478bd9Sstevel@tonic-gate return; 625*7c478bd9Sstevel@tonic-gate } 626*7c478bd9Sstevel@tonic-gate } 627*7c478bd9Sstevel@tonic-gate 628*7c478bd9Sstevel@tonic-gate callstack = Stk->next; 629*7c478bd9Sstevel@tonic-gate nstack--; 630*7c478bd9Sstevel@tonic-gate free(Stk->stack); 631*7c478bd9Sstevel@tonic-gate free(Stk); 632*7c478bd9Sstevel@tonic-gate } 633*7c478bd9Sstevel@tonic-gate 634*7c478bd9Sstevel@tonic-gate void 635*7c478bd9Sstevel@tonic-gate make_thr_stack(const td_thrhandle_t *Thp, prgregset_t reg) 636*7c478bd9Sstevel@tonic-gate { 637*7c478bd9Sstevel@tonic-gate const pstatus_t *Psp = Pstatus(Proc); 638*7c478bd9Sstevel@tonic-gate td_thrinfo_t thrinfo; 639*7c478bd9Sstevel@tonic-gate uintptr_t sp = reg[R_SP]; 640*7c478bd9Sstevel@tonic-gate struct callstack *Stk; 641*7c478bd9Sstevel@tonic-gate 642*7c478bd9Sstevel@tonic-gate if (data_model != PR_MODEL_LP64) 643*7c478bd9Sstevel@tonic-gate sp = (uint32_t)sp; 644*7c478bd9Sstevel@tonic-gate 645*7c478bd9Sstevel@tonic-gate /* check to see if we already have this stack */ 646*7c478bd9Sstevel@tonic-gate if (sp == 0) 647*7c478bd9Sstevel@tonic-gate return; 648*7c478bd9Sstevel@tonic-gate for (Stk = callstack; Stk != NULL; Stk = Stk->next) 649*7c478bd9Sstevel@tonic-gate if (sp >= Stk->stkbase && sp < Stk->stkend) 650*7c478bd9Sstevel@tonic-gate return; 651*7c478bd9Sstevel@tonic-gate 652*7c478bd9Sstevel@tonic-gate Stk = my_malloc(sizeof (struct callstack), NULL); 653*7c478bd9Sstevel@tonic-gate Stk->next = callstack; 654*7c478bd9Sstevel@tonic-gate callstack = Stk; 655*7c478bd9Sstevel@tonic-gate nstack++; 656*7c478bd9Sstevel@tonic-gate Stk->tref = 0; 657*7c478bd9Sstevel@tonic-gate Stk->tid = 0; 658*7c478bd9Sstevel@tonic-gate Stk->nthr_create = 0; 659*7c478bd9Sstevel@tonic-gate Stk->ncall = 0; 660*7c478bd9Sstevel@tonic-gate Stk->maxcall = DEF_MAXCALL; 661*7c478bd9Sstevel@tonic-gate Stk->stack = my_malloc(DEF_MAXCALL * sizeof (*Stk->stack), NULL); 662*7c478bd9Sstevel@tonic-gate 663*7c478bd9Sstevel@tonic-gate /* primary stack */ 664*7c478bd9Sstevel@tonic-gate if (sp >= Psp->pr_stkbase && sp < Psp->pr_stkbase + Psp->pr_stksize) { 665*7c478bd9Sstevel@tonic-gate Stk->stkbase = Psp->pr_stkbase; 666*7c478bd9Sstevel@tonic-gate Stk->stkend = Stk->stkbase + Psp->pr_stksize; 667*7c478bd9Sstevel@tonic-gate return; 668*7c478bd9Sstevel@tonic-gate } 669*7c478bd9Sstevel@tonic-gate 670*7c478bd9Sstevel@tonic-gate if (td_thr_get_info(Thp, &thrinfo) == TD_OK && 671*7c478bd9Sstevel@tonic-gate sp >= (uintptr_t)thrinfo.ti_stkbase - thrinfo.ti_stksize && 672*7c478bd9Sstevel@tonic-gate sp < (uintptr_t)thrinfo.ti_stkbase) { 673*7c478bd9Sstevel@tonic-gate /* The bloody fools got this backwards! */ 674*7c478bd9Sstevel@tonic-gate Stk->stkend = (uintptr_t)thrinfo.ti_stkbase; 675*7c478bd9Sstevel@tonic-gate Stk->stkbase = Stk->stkend - thrinfo.ti_stksize; 676*7c478bd9Sstevel@tonic-gate return; 677*7c478bd9Sstevel@tonic-gate } 678*7c478bd9Sstevel@tonic-gate 679*7c478bd9Sstevel@tonic-gate callstack = Stk->next; 680*7c478bd9Sstevel@tonic-gate nstack--; 681*7c478bd9Sstevel@tonic-gate free(Stk->stack); 682*7c478bd9Sstevel@tonic-gate free(Stk); 683*7c478bd9Sstevel@tonic-gate } 684*7c478bd9Sstevel@tonic-gate 685*7c478bd9Sstevel@tonic-gate struct callstack * 686*7c478bd9Sstevel@tonic-gate find_lwp_stack(uintptr_t sp) 687*7c478bd9Sstevel@tonic-gate { 688*7c478bd9Sstevel@tonic-gate const pstatus_t *Psp = Pstatus(Proc); 689*7c478bd9Sstevel@tonic-gate char mapfile[64]; 690*7c478bd9Sstevel@tonic-gate int mapfd; 691*7c478bd9Sstevel@tonic-gate struct stat statb; 692*7c478bd9Sstevel@tonic-gate prmap_t *Pmap = NULL; 693*7c478bd9Sstevel@tonic-gate prmap_t *pmap = NULL; 694*7c478bd9Sstevel@tonic-gate int nmap = 0; 695*7c478bd9Sstevel@tonic-gate struct callstack *Stk = NULL; 696*7c478bd9Sstevel@tonic-gate 697*7c478bd9Sstevel@tonic-gate /* 698*7c478bd9Sstevel@tonic-gate * Get the address space map. 699*7c478bd9Sstevel@tonic-gate */ 700*7c478bd9Sstevel@tonic-gate (void) sprintf(mapfile, "/proc/%d/rmap", (int)Psp->pr_pid); 701*7c478bd9Sstevel@tonic-gate if ((mapfd = open(mapfile, O_RDONLY)) < 0 || 702*7c478bd9Sstevel@tonic-gate fstat(mapfd, &statb) != 0 || 703*7c478bd9Sstevel@tonic-gate statb.st_size < sizeof (prmap_t) || 704*7c478bd9Sstevel@tonic-gate (Pmap = my_malloc(statb.st_size, NULL)) == NULL || 705*7c478bd9Sstevel@tonic-gate (nmap = pread(mapfd, Pmap, statb.st_size, 0L)) <= 0 || 706*7c478bd9Sstevel@tonic-gate (nmap /= sizeof (prmap_t)) == 0) { 707*7c478bd9Sstevel@tonic-gate if (Pmap != NULL) 708*7c478bd9Sstevel@tonic-gate free(Pmap); 709*7c478bd9Sstevel@tonic-gate if (mapfd >= 0) 710*7c478bd9Sstevel@tonic-gate (void) close(mapfd); 711*7c478bd9Sstevel@tonic-gate return (NULL); 712*7c478bd9Sstevel@tonic-gate } 713*7c478bd9Sstevel@tonic-gate (void) close(mapfd); 714*7c478bd9Sstevel@tonic-gate 715*7c478bd9Sstevel@tonic-gate for (pmap = Pmap; nmap--; pmap++) { 716*7c478bd9Sstevel@tonic-gate if (sp >= pmap->pr_vaddr && 717*7c478bd9Sstevel@tonic-gate sp < pmap->pr_vaddr + pmap->pr_size) { 718*7c478bd9Sstevel@tonic-gate Stk = my_malloc(sizeof (struct callstack), NULL); 719*7c478bd9Sstevel@tonic-gate Stk->next = callstack; 720*7c478bd9Sstevel@tonic-gate callstack = Stk; 721*7c478bd9Sstevel@tonic-gate nstack++; 722*7c478bd9Sstevel@tonic-gate Stk->stkbase = pmap->pr_vaddr; 723*7c478bd9Sstevel@tonic-gate Stk->stkend = pmap->pr_vaddr + pmap->pr_size; 724*7c478bd9Sstevel@tonic-gate Stk->tref = 0; 725*7c478bd9Sstevel@tonic-gate Stk->tid = 0; 726*7c478bd9Sstevel@tonic-gate Stk->nthr_create = 0; 727*7c478bd9Sstevel@tonic-gate Stk->ncall = 0; 728*7c478bd9Sstevel@tonic-gate Stk->maxcall = DEF_MAXCALL; 729*7c478bd9Sstevel@tonic-gate Stk->stack = my_malloc( 730*7c478bd9Sstevel@tonic-gate DEF_MAXCALL * sizeof (*Stk->stack), NULL); 731*7c478bd9Sstevel@tonic-gate break; 732*7c478bd9Sstevel@tonic-gate } 733*7c478bd9Sstevel@tonic-gate } 734*7c478bd9Sstevel@tonic-gate 735*7c478bd9Sstevel@tonic-gate free(Pmap); 736*7c478bd9Sstevel@tonic-gate return (Stk); 737*7c478bd9Sstevel@tonic-gate } 738*7c478bd9Sstevel@tonic-gate 739*7c478bd9Sstevel@tonic-gate struct callstack * 740*7c478bd9Sstevel@tonic-gate find_stack(uintptr_t sp) 741*7c478bd9Sstevel@tonic-gate { 742*7c478bd9Sstevel@tonic-gate const pstatus_t *Psp = Pstatus(Proc); 743*7c478bd9Sstevel@tonic-gate private_t *pri = get_private(); 744*7c478bd9Sstevel@tonic-gate const lwpstatus_t *Lsp = pri->lwpstat; 745*7c478bd9Sstevel@tonic-gate id_t lwpid = Lsp->pr_lwpid; 746*7c478bd9Sstevel@tonic-gate #if defined(__sparc) 747*7c478bd9Sstevel@tonic-gate prgreg_t tref = Lsp->pr_reg[R_G7]; 748*7c478bd9Sstevel@tonic-gate #elif defined(__amd64) 749*7c478bd9Sstevel@tonic-gate prgreg_t tref = Lsp->pr_reg[REG_FS]; 750*7c478bd9Sstevel@tonic-gate #elif defined(__i386) 751*7c478bd9Sstevel@tonic-gate prgreg_t tref = Lsp->pr_reg[GS]; 752*7c478bd9Sstevel@tonic-gate #endif 753*7c478bd9Sstevel@tonic-gate struct callstack *Stk = NULL; 754*7c478bd9Sstevel@tonic-gate td_thrhandle_t th; 755*7c478bd9Sstevel@tonic-gate td_thrinfo_t thrinfo; 756*7c478bd9Sstevel@tonic-gate td_err_e error; 757*7c478bd9Sstevel@tonic-gate 758*7c478bd9Sstevel@tonic-gate /* primary stack */ 759*7c478bd9Sstevel@tonic-gate if (sp >= Psp->pr_stkbase && sp < Psp->pr_stkbase + Psp->pr_stksize) { 760*7c478bd9Sstevel@tonic-gate Stk = my_malloc(sizeof (struct callstack), NULL); 761*7c478bd9Sstevel@tonic-gate Stk->next = callstack; 762*7c478bd9Sstevel@tonic-gate callstack = Stk; 763*7c478bd9Sstevel@tonic-gate nstack++; 764*7c478bd9Sstevel@tonic-gate Stk->stkbase = Psp->pr_stkbase; 765*7c478bd9Sstevel@tonic-gate Stk->stkend = Stk->stkbase + Psp->pr_stksize; 766*7c478bd9Sstevel@tonic-gate Stk->tref = 0; 767*7c478bd9Sstevel@tonic-gate Stk->tid = 0; 768*7c478bd9Sstevel@tonic-gate Stk->nthr_create = 0; 769*7c478bd9Sstevel@tonic-gate Stk->ncall = 0; 770*7c478bd9Sstevel@tonic-gate Stk->maxcall = DEF_MAXCALL; 771*7c478bd9Sstevel@tonic-gate Stk->stack = my_malloc(DEF_MAXCALL * sizeof (*Stk->stack), 772*7c478bd9Sstevel@tonic-gate NULL); 773*7c478bd9Sstevel@tonic-gate return (Stk); 774*7c478bd9Sstevel@tonic-gate } 775*7c478bd9Sstevel@tonic-gate 776*7c478bd9Sstevel@tonic-gate /* alternate stack */ 777*7c478bd9Sstevel@tonic-gate if ((Lsp->pr_altstack.ss_flags & SS_ONSTACK) && 778*7c478bd9Sstevel@tonic-gate sp >= (uintptr_t)Lsp->pr_altstack.ss_sp && 779*7c478bd9Sstevel@tonic-gate sp < (uintptr_t)Lsp->pr_altstack.ss_sp 780*7c478bd9Sstevel@tonic-gate + Lsp->pr_altstack.ss_size) { 781*7c478bd9Sstevel@tonic-gate Stk = my_malloc(sizeof (struct callstack), NULL); 782*7c478bd9Sstevel@tonic-gate Stk->next = callstack; 783*7c478bd9Sstevel@tonic-gate callstack = Stk; 784*7c478bd9Sstevel@tonic-gate nstack++; 785*7c478bd9Sstevel@tonic-gate Stk->stkbase = (uintptr_t)Lsp->pr_altstack.ss_sp; 786*7c478bd9Sstevel@tonic-gate Stk->stkend = Stk->stkbase + Lsp->pr_altstack.ss_size; 787*7c478bd9Sstevel@tonic-gate Stk->tref = 0; 788*7c478bd9Sstevel@tonic-gate Stk->tid = 0; 789*7c478bd9Sstevel@tonic-gate Stk->nthr_create = 0; 790*7c478bd9Sstevel@tonic-gate Stk->ncall = 0; 791*7c478bd9Sstevel@tonic-gate Stk->maxcall = DEF_MAXCALL; 792*7c478bd9Sstevel@tonic-gate Stk->stack = my_malloc(DEF_MAXCALL * sizeof (*Stk->stack), 793*7c478bd9Sstevel@tonic-gate NULL); 794*7c478bd9Sstevel@tonic-gate return (Stk); 795*7c478bd9Sstevel@tonic-gate } 796*7c478bd9Sstevel@tonic-gate 797*7c478bd9Sstevel@tonic-gate if (Thr_agent == NULL) 798*7c478bd9Sstevel@tonic-gate return (find_lwp_stack(sp)); 799*7c478bd9Sstevel@tonic-gate 800*7c478bd9Sstevel@tonic-gate /* thread stacks? */ 801*7c478bd9Sstevel@tonic-gate if ((error = td_ta_map_lwp2thr(Thr_agent, lwpid, &th)) != TD_OK) { 802*7c478bd9Sstevel@tonic-gate if (hflag) 803*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 804*7c478bd9Sstevel@tonic-gate "cannot get thread handle for " 805*7c478bd9Sstevel@tonic-gate "lwp#%d, error=%d, tref=0x%.8lx\n", 806*7c478bd9Sstevel@tonic-gate (int)lwpid, error, (long)tref); 807*7c478bd9Sstevel@tonic-gate return (NULL); 808*7c478bd9Sstevel@tonic-gate } 809*7c478bd9Sstevel@tonic-gate 810*7c478bd9Sstevel@tonic-gate if ((error = td_thr_get_info(&th, &thrinfo)) != TD_OK) { 811*7c478bd9Sstevel@tonic-gate if (hflag) 812*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 813*7c478bd9Sstevel@tonic-gate "cannot get thread info for " 814*7c478bd9Sstevel@tonic-gate "lwp#%d, error=%d, tref=0x%.8lx\n", 815*7c478bd9Sstevel@tonic-gate (int)lwpid, error, (long)tref); 816*7c478bd9Sstevel@tonic-gate return (NULL); 817*7c478bd9Sstevel@tonic-gate } 818*7c478bd9Sstevel@tonic-gate 819*7c478bd9Sstevel@tonic-gate if (sp >= (uintptr_t)thrinfo.ti_stkbase - thrinfo.ti_stksize && 820*7c478bd9Sstevel@tonic-gate sp < (uintptr_t)thrinfo.ti_stkbase) { 821*7c478bd9Sstevel@tonic-gate Stk = my_malloc(sizeof (struct callstack), NULL); 822*7c478bd9Sstevel@tonic-gate Stk->next = callstack; 823*7c478bd9Sstevel@tonic-gate callstack = Stk; 824*7c478bd9Sstevel@tonic-gate nstack++; 825*7c478bd9Sstevel@tonic-gate /* The bloody fools got this backwards! */ 826*7c478bd9Sstevel@tonic-gate Stk->stkend = (uintptr_t)thrinfo.ti_stkbase; 827*7c478bd9Sstevel@tonic-gate Stk->stkbase = Stk->stkend - thrinfo.ti_stksize; 828*7c478bd9Sstevel@tonic-gate Stk->tref = tref; 829*7c478bd9Sstevel@tonic-gate Stk->tid = thrinfo.ti_tid; 830*7c478bd9Sstevel@tonic-gate Stk->nthr_create = nthr_create; 831*7c478bd9Sstevel@tonic-gate Stk->ncall = 0; 832*7c478bd9Sstevel@tonic-gate Stk->maxcall = DEF_MAXCALL; 833*7c478bd9Sstevel@tonic-gate Stk->stack = my_malloc(DEF_MAXCALL * sizeof (*Stk->stack), 834*7c478bd9Sstevel@tonic-gate NULL); 835*7c478bd9Sstevel@tonic-gate return (Stk); 836*7c478bd9Sstevel@tonic-gate } 837*7c478bd9Sstevel@tonic-gate 838*7c478bd9Sstevel@tonic-gate /* stack bounds failure -- complain bitterly */ 839*7c478bd9Sstevel@tonic-gate if (hflag) { 840*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 841*7c478bd9Sstevel@tonic-gate "sp not within thread stack: " 842*7c478bd9Sstevel@tonic-gate "sp=0x%.8lx stkbase=0x%.8lx stkend=0x%.8lx\n", 843*7c478bd9Sstevel@tonic-gate (ulong_t)sp, 844*7c478bd9Sstevel@tonic-gate /* The bloody fools got this backwards! */ 845*7c478bd9Sstevel@tonic-gate (ulong_t)thrinfo.ti_stkbase - thrinfo.ti_stksize, 846*7c478bd9Sstevel@tonic-gate (ulong_t)thrinfo.ti_stkbase); 847*7c478bd9Sstevel@tonic-gate } 848*7c478bd9Sstevel@tonic-gate 849*7c478bd9Sstevel@tonic-gate return (NULL); 850*7c478bd9Sstevel@tonic-gate } 851*7c478bd9Sstevel@tonic-gate 852*7c478bd9Sstevel@tonic-gate void 853*7c478bd9Sstevel@tonic-gate get_tid(struct callstack *Stk) 854*7c478bd9Sstevel@tonic-gate { 855*7c478bd9Sstevel@tonic-gate private_t *pri = get_private(); 856*7c478bd9Sstevel@tonic-gate const lwpstatus_t *Lsp = pri->lwpstat; 857*7c478bd9Sstevel@tonic-gate id_t lwpid = Lsp->pr_lwpid; 858*7c478bd9Sstevel@tonic-gate #if defined(__sparc) 859*7c478bd9Sstevel@tonic-gate prgreg_t tref = Lsp->pr_reg[R_G7]; 860*7c478bd9Sstevel@tonic-gate #elif defined(__amd64) 861*7c478bd9Sstevel@tonic-gate prgreg_t tref = (data_model == PR_MODEL_LP64) ? 862*7c478bd9Sstevel@tonic-gate Lsp->pr_reg[REG_FS] : Lsp->pr_reg[REG_GS]; 863*7c478bd9Sstevel@tonic-gate #elif defined(__i386) 864*7c478bd9Sstevel@tonic-gate prgreg_t tref = Lsp->pr_reg[GS]; 865*7c478bd9Sstevel@tonic-gate #endif 866*7c478bd9Sstevel@tonic-gate td_thrhandle_t th; 867*7c478bd9Sstevel@tonic-gate td_thrinfo_t thrinfo; 868*7c478bd9Sstevel@tonic-gate td_err_e error; 869*7c478bd9Sstevel@tonic-gate 870*7c478bd9Sstevel@tonic-gate if (Thr_agent == NULL) { 871*7c478bd9Sstevel@tonic-gate Stk->tref = 0; 872*7c478bd9Sstevel@tonic-gate Stk->tid = 0; 873*7c478bd9Sstevel@tonic-gate Stk->nthr_create = 0; 874*7c478bd9Sstevel@tonic-gate return; 875*7c478bd9Sstevel@tonic-gate } 876*7c478bd9Sstevel@tonic-gate 877*7c478bd9Sstevel@tonic-gate /* 878*7c478bd9Sstevel@tonic-gate * Shortcut here -- 879*7c478bd9Sstevel@tonic-gate * If we have a matching tref and no new threads have 880*7c478bd9Sstevel@tonic-gate * been created since the last time we encountered this 881*7c478bd9Sstevel@tonic-gate * stack, then we don't have to go through the overhead 882*7c478bd9Sstevel@tonic-gate * of calling td_ta_map_lwp2thr() to get the thread-id. 883*7c478bd9Sstevel@tonic-gate */ 884*7c478bd9Sstevel@tonic-gate if (tref == Stk->tref && Stk->nthr_create == nthr_create) 885*7c478bd9Sstevel@tonic-gate return; 886*7c478bd9Sstevel@tonic-gate 887*7c478bd9Sstevel@tonic-gate if ((error = td_ta_map_lwp2thr(Thr_agent, lwpid, &th)) != TD_OK) { 888*7c478bd9Sstevel@tonic-gate if (hflag) 889*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 890*7c478bd9Sstevel@tonic-gate "cannot get thread handle for " 891*7c478bd9Sstevel@tonic-gate "lwp#%d, error=%d, tref=0x%.8lx\n", 892*7c478bd9Sstevel@tonic-gate (int)lwpid, error, (long)tref); 893*7c478bd9Sstevel@tonic-gate Stk->tref = 0; 894*7c478bd9Sstevel@tonic-gate Stk->tid = 0; 895*7c478bd9Sstevel@tonic-gate Stk->nthr_create = 0; 896*7c478bd9Sstevel@tonic-gate } else if ((error = td_thr_get_info(&th, &thrinfo)) != TD_OK) { 897*7c478bd9Sstevel@tonic-gate if (hflag) 898*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 899*7c478bd9Sstevel@tonic-gate "cannot get thread info for " 900*7c478bd9Sstevel@tonic-gate "lwp#%d, error=%d, tref=0x%.8lx\n", 901*7c478bd9Sstevel@tonic-gate (int)lwpid, error, (long)tref); 902*7c478bd9Sstevel@tonic-gate Stk->tref = 0; 903*7c478bd9Sstevel@tonic-gate Stk->tid = 0; 904*7c478bd9Sstevel@tonic-gate Stk->nthr_create = 0; 905*7c478bd9Sstevel@tonic-gate } else { 906*7c478bd9Sstevel@tonic-gate Stk->tref = tref; 907*7c478bd9Sstevel@tonic-gate Stk->tid = thrinfo.ti_tid; 908*7c478bd9Sstevel@tonic-gate Stk->nthr_create = nthr_create; 909*7c478bd9Sstevel@tonic-gate } 910*7c478bd9Sstevel@tonic-gate } 911*7c478bd9Sstevel@tonic-gate 912*7c478bd9Sstevel@tonic-gate struct callstack * 913*7c478bd9Sstevel@tonic-gate callstack_info(uintptr_t sp, uintptr_t fp, int makeid) 914*7c478bd9Sstevel@tonic-gate { 915*7c478bd9Sstevel@tonic-gate struct callstack *Stk; 916*7c478bd9Sstevel@tonic-gate uintptr_t trash; 917*7c478bd9Sstevel@tonic-gate 918*7c478bd9Sstevel@tonic-gate if (sp == 0 || 919*7c478bd9Sstevel@tonic-gate Pread(Proc, &trash, sizeof (trash), sp) != sizeof (trash)) 920*7c478bd9Sstevel@tonic-gate return (NULL); 921*7c478bd9Sstevel@tonic-gate 922*7c478bd9Sstevel@tonic-gate for (Stk = callstack; Stk != NULL; Stk = Stk->next) 923*7c478bd9Sstevel@tonic-gate if (sp >= Stk->stkbase && sp < Stk->stkend) 924*7c478bd9Sstevel@tonic-gate break; 925*7c478bd9Sstevel@tonic-gate 926*7c478bd9Sstevel@tonic-gate /* 927*7c478bd9Sstevel@tonic-gate * If we didn't find the stack, do it the hard way. 928*7c478bd9Sstevel@tonic-gate */ 929*7c478bd9Sstevel@tonic-gate if (Stk == NULL) { 930*7c478bd9Sstevel@tonic-gate uintptr_t stkbase = sp; 931*7c478bd9Sstevel@tonic-gate uintptr_t stkend; 932*7c478bd9Sstevel@tonic-gate uint_t minsize; 933*7c478bd9Sstevel@tonic-gate 934*7c478bd9Sstevel@tonic-gate #if defined(i386) || defined(__amd64) 935*7c478bd9Sstevel@tonic-gate #ifdef _LP64 936*7c478bd9Sstevel@tonic-gate if (data_model == PR_MODEL_LP64) 937*7c478bd9Sstevel@tonic-gate minsize = 2 * sizeof (uintptr_t); /* fp + pc */ 938*7c478bd9Sstevel@tonic-gate else 939*7c478bd9Sstevel@tonic-gate #endif 940*7c478bd9Sstevel@tonic-gate minsize = 2 * sizeof (uint32_t); 941*7c478bd9Sstevel@tonic-gate #else 942*7c478bd9Sstevel@tonic-gate #ifdef _LP64 943*7c478bd9Sstevel@tonic-gate if (data_model != PR_MODEL_LP64) 944*7c478bd9Sstevel@tonic-gate minsize = SA32(MINFRAME32); 945*7c478bd9Sstevel@tonic-gate else 946*7c478bd9Sstevel@tonic-gate minsize = SA64(MINFRAME64); 947*7c478bd9Sstevel@tonic-gate #else 948*7c478bd9Sstevel@tonic-gate minsize = SA(MINFRAME); 949*7c478bd9Sstevel@tonic-gate #endif 950*7c478bd9Sstevel@tonic-gate #endif /* i386 */ 951*7c478bd9Sstevel@tonic-gate stkend = sp + minsize; 952*7c478bd9Sstevel@tonic-gate 953*7c478bd9Sstevel@tonic-gate while (Stk == NULL && fp != 0 && fp >= sp) { 954*7c478bd9Sstevel@tonic-gate stkend = fp + minsize; 955*7c478bd9Sstevel@tonic-gate for (Stk = callstack; Stk != NULL; Stk = Stk->next) 956*7c478bd9Sstevel@tonic-gate if ((fp >= Stk->stkbase && fp < Stk->stkend) || 957*7c478bd9Sstevel@tonic-gate (stkend > Stk->stkbase && 958*7c478bd9Sstevel@tonic-gate stkend <= Stk->stkend)) 959*7c478bd9Sstevel@tonic-gate break; 960*7c478bd9Sstevel@tonic-gate if (Stk == NULL) 961*7c478bd9Sstevel@tonic-gate fp = previous_fp(fp, NULL); 962*7c478bd9Sstevel@tonic-gate } 963*7c478bd9Sstevel@tonic-gate 964*7c478bd9Sstevel@tonic-gate if (Stk != NULL) /* the stack grew */ 965*7c478bd9Sstevel@tonic-gate Stk->stkbase = stkbase; 966*7c478bd9Sstevel@tonic-gate } 967*7c478bd9Sstevel@tonic-gate 968*7c478bd9Sstevel@tonic-gate if (Stk == NULL && makeid) /* new stack */ 969*7c478bd9Sstevel@tonic-gate Stk = find_stack(sp); 970*7c478bd9Sstevel@tonic-gate 971*7c478bd9Sstevel@tonic-gate if (Stk == NULL) 972*7c478bd9Sstevel@tonic-gate return (NULL); 973*7c478bd9Sstevel@tonic-gate 974*7c478bd9Sstevel@tonic-gate /* 975*7c478bd9Sstevel@tonic-gate * Ensure that there is room for at least one more entry. 976*7c478bd9Sstevel@tonic-gate */ 977*7c478bd9Sstevel@tonic-gate if (Stk->ncall == Stk->maxcall) { 978*7c478bd9Sstevel@tonic-gate Stk->maxcall *= 2; 979*7c478bd9Sstevel@tonic-gate Stk->stack = my_realloc(Stk->stack, 980*7c478bd9Sstevel@tonic-gate Stk->maxcall * sizeof (*Stk->stack), NULL); 981*7c478bd9Sstevel@tonic-gate } 982*7c478bd9Sstevel@tonic-gate 983*7c478bd9Sstevel@tonic-gate if (makeid) 984*7c478bd9Sstevel@tonic-gate get_tid(Stk); 985*7c478bd9Sstevel@tonic-gate 986*7c478bd9Sstevel@tonic-gate return (Stk); 987*7c478bd9Sstevel@tonic-gate } 988*7c478bd9Sstevel@tonic-gate 989*7c478bd9Sstevel@tonic-gate /* 990*7c478bd9Sstevel@tonic-gate * Reset the breakpoint information (called on successful exec()). 991*7c478bd9Sstevel@tonic-gate */ 992*7c478bd9Sstevel@tonic-gate void 993*7c478bd9Sstevel@tonic-gate reset_breakpoints(void) 994*7c478bd9Sstevel@tonic-gate { 995*7c478bd9Sstevel@tonic-gate struct dynlib *Dp; 996*7c478bd9Sstevel@tonic-gate struct bkpt *Bp; 997*7c478bd9Sstevel@tonic-gate struct callstack *Stk; 998*7c478bd9Sstevel@tonic-gate int i; 999*7c478bd9Sstevel@tonic-gate 1000*7c478bd9Sstevel@tonic-gate if (Dynpat == NULL) 1001*7c478bd9Sstevel@tonic-gate return; 1002*7c478bd9Sstevel@tonic-gate 1003*7c478bd9Sstevel@tonic-gate /* destroy all previous dynamic library information */ 1004*7c478bd9Sstevel@tonic-gate while ((Dp = Dyn) != NULL) { 1005*7c478bd9Sstevel@tonic-gate Dyn = Dp->next; 1006*7c478bd9Sstevel@tonic-gate free(Dp->lib_name); 1007*7c478bd9Sstevel@tonic-gate free(Dp->match_name); 1008*7c478bd9Sstevel@tonic-gate free(Dp->prt_name); 1009*7c478bd9Sstevel@tonic-gate free(Dp); 1010*7c478bd9Sstevel@tonic-gate } 1011*7c478bd9Sstevel@tonic-gate 1012*7c478bd9Sstevel@tonic-gate /* destroy all previous breakpoint trap information */ 1013*7c478bd9Sstevel@tonic-gate if (bpt_hashtable != NULL) { 1014*7c478bd9Sstevel@tonic-gate for (i = 0; i < HASHSZ; i++) { 1015*7c478bd9Sstevel@tonic-gate while ((Bp = bpt_hashtable[i]) != NULL) { 1016*7c478bd9Sstevel@tonic-gate bpt_hashtable[i] = Bp->next; 1017*7c478bd9Sstevel@tonic-gate if (Bp->sym_name) 1018*7c478bd9Sstevel@tonic-gate free(Bp->sym_name); 1019*7c478bd9Sstevel@tonic-gate free(Bp); 1020*7c478bd9Sstevel@tonic-gate } 1021*7c478bd9Sstevel@tonic-gate } 1022*7c478bd9Sstevel@tonic-gate } 1023*7c478bd9Sstevel@tonic-gate 1024*7c478bd9Sstevel@tonic-gate /* destroy all the callstack information */ 1025*7c478bd9Sstevel@tonic-gate while ((Stk = callstack) != NULL) { 1026*7c478bd9Sstevel@tonic-gate callstack = Stk->next; 1027*7c478bd9Sstevel@tonic-gate free(Stk->stack); 1028*7c478bd9Sstevel@tonic-gate free(Stk); 1029*7c478bd9Sstevel@tonic-gate } 1030*7c478bd9Sstevel@tonic-gate 1031*7c478bd9Sstevel@tonic-gate /* we are not a multi-threaded process anymore */ 1032*7c478bd9Sstevel@tonic-gate if (Thr_agent != NULL) 1033*7c478bd9Sstevel@tonic-gate (void) td_ta_delete(Thr_agent); 1034*7c478bd9Sstevel@tonic-gate Thr_agent = NULL; 1035*7c478bd9Sstevel@tonic-gate 1036*7c478bd9Sstevel@tonic-gate /* tell libproc to clear out its mapping information */ 1037*7c478bd9Sstevel@tonic-gate Preset_maps(Proc); 1038*7c478bd9Sstevel@tonic-gate Rdb_agent = NULL; 1039*7c478bd9Sstevel@tonic-gate 1040*7c478bd9Sstevel@tonic-gate /* Reestablish the symbols from the executable */ 1041*7c478bd9Sstevel@tonic-gate (void) establish_breakpoints(); 1042*7c478bd9Sstevel@tonic-gate } 1043*7c478bd9Sstevel@tonic-gate 1044*7c478bd9Sstevel@tonic-gate /* 1045*7c478bd9Sstevel@tonic-gate * Clear breakpoints from the process (called before Prelease()). 1046*7c478bd9Sstevel@tonic-gate * Don't actually destroy the breakpoint table; 1047*7c478bd9Sstevel@tonic-gate * threads currently fielding breakpoints will need it. 1048*7c478bd9Sstevel@tonic-gate */ 1049*7c478bd9Sstevel@tonic-gate void 1050*7c478bd9Sstevel@tonic-gate clear_breakpoints(void) 1051*7c478bd9Sstevel@tonic-gate { 1052*7c478bd9Sstevel@tonic-gate struct bkpt *Bp; 1053*7c478bd9Sstevel@tonic-gate int i; 1054*7c478bd9Sstevel@tonic-gate 1055*7c478bd9Sstevel@tonic-gate if (Dynpat == NULL) 1056*7c478bd9Sstevel@tonic-gate return; 1057*7c478bd9Sstevel@tonic-gate 1058*7c478bd9Sstevel@tonic-gate /* 1059*7c478bd9Sstevel@tonic-gate * Change all breakpoint traps back to normal instructions. 1060*7c478bd9Sstevel@tonic-gate * We attempt to remove a breakpoint from every address which 1061*7c478bd9Sstevel@tonic-gate * may have ever contained a breakpoint to protect our victims. 1062*7c478bd9Sstevel@tonic-gate */ 1063*7c478bd9Sstevel@tonic-gate report_htable_stats(); /* report stats first */ 1064*7c478bd9Sstevel@tonic-gate for (i = 0; i < HASHSZ; i++) { 1065*7c478bd9Sstevel@tonic-gate for (Bp = bpt_hashtable[i]; Bp != NULL; Bp = Bp->next) { 1066*7c478bd9Sstevel@tonic-gate if (Bp->flags & BPT_ACTIVE) 1067*7c478bd9Sstevel@tonic-gate (void) Pdelbkpt(Proc, Bp->addr, Bp->instr); 1068*7c478bd9Sstevel@tonic-gate Bp->flags &= ~BPT_ACTIVE; 1069*7c478bd9Sstevel@tonic-gate } 1070*7c478bd9Sstevel@tonic-gate } 1071*7c478bd9Sstevel@tonic-gate 1072*7c478bd9Sstevel@tonic-gate if (Thr_agent != NULL) { 1073*7c478bd9Sstevel@tonic-gate td_thr_events_t events; 1074*7c478bd9Sstevel@tonic-gate 1075*7c478bd9Sstevel@tonic-gate td_event_emptyset(&events); 1076*7c478bd9Sstevel@tonic-gate (void) td_ta_set_event(Thr_agent, &events); 1077*7c478bd9Sstevel@tonic-gate (void) td_ta_delete(Thr_agent); 1078*7c478bd9Sstevel@tonic-gate } 1079*7c478bd9Sstevel@tonic-gate Thr_agent = NULL; 1080*7c478bd9Sstevel@tonic-gate } 1081*7c478bd9Sstevel@tonic-gate 1082*7c478bd9Sstevel@tonic-gate /* 1083*7c478bd9Sstevel@tonic-gate * Reestablish the breakpoint traps in the process. 1084*7c478bd9Sstevel@tonic-gate * Called after resuming from a vfork() in the parent. 1085*7c478bd9Sstevel@tonic-gate */ 1086*7c478bd9Sstevel@tonic-gate void 1087*7c478bd9Sstevel@tonic-gate reestablish_traps(void) 1088*7c478bd9Sstevel@tonic-gate { 1089*7c478bd9Sstevel@tonic-gate struct bkpt *Bp; 1090*7c478bd9Sstevel@tonic-gate ulong_t instr; 1091*7c478bd9Sstevel@tonic-gate int i; 1092*7c478bd9Sstevel@tonic-gate 1093*7c478bd9Sstevel@tonic-gate if (Dynpat == NULL || is_vfork_child) 1094*7c478bd9Sstevel@tonic-gate return; 1095*7c478bd9Sstevel@tonic-gate 1096*7c478bd9Sstevel@tonic-gate for (i = 0; i < HASHSZ; i++) { 1097*7c478bd9Sstevel@tonic-gate for (Bp = bpt_hashtable[i]; Bp != NULL; Bp = Bp->next) { 1098*7c478bd9Sstevel@tonic-gate if ((Bp->flags & BPT_ACTIVE) && 1099*7c478bd9Sstevel@tonic-gate Psetbkpt(Proc, Bp->addr, &instr) != 0) 1100*7c478bd9Sstevel@tonic-gate Bp->flags &= ~BPT_ACTIVE; 1101*7c478bd9Sstevel@tonic-gate } 1102*7c478bd9Sstevel@tonic-gate } 1103*7c478bd9Sstevel@tonic-gate } 1104*7c478bd9Sstevel@tonic-gate 1105*7c478bd9Sstevel@tonic-gate void 1106*7c478bd9Sstevel@tonic-gate show_function_call(private_t *pri, 1107*7c478bd9Sstevel@tonic-gate struct callstack *Stk, struct dynlib *Dp, struct bkpt *Bp) 1108*7c478bd9Sstevel@tonic-gate { 1109*7c478bd9Sstevel@tonic-gate long arg[8]; 1110*7c478bd9Sstevel@tonic-gate int narg; 1111*7c478bd9Sstevel@tonic-gate int i; 1112*7c478bd9Sstevel@tonic-gate 1113*7c478bd9Sstevel@tonic-gate narg = get_arguments(arg); 1114*7c478bd9Sstevel@tonic-gate make_pname(pri, (Stk != NULL)? Stk->tid : 0); 1115*7c478bd9Sstevel@tonic-gate putpname(pri); 1116*7c478bd9Sstevel@tonic-gate timestamp(pri); 1117*7c478bd9Sstevel@tonic-gate if (Stk != NULL) { 1118*7c478bd9Sstevel@tonic-gate for (i = 1; i < Stk->ncall; i++) { 1119*7c478bd9Sstevel@tonic-gate (void) fputc(' ', stdout); 1120*7c478bd9Sstevel@tonic-gate (void) fputc(' ', stdout); 1121*7c478bd9Sstevel@tonic-gate } 1122*7c478bd9Sstevel@tonic-gate } 1123*7c478bd9Sstevel@tonic-gate (void) printf("-> %s%s(", Dp->prt_name, Bp->sym_name); 1124*7c478bd9Sstevel@tonic-gate for (i = 0; i < narg; i++) { 1125*7c478bd9Sstevel@tonic-gate (void) printf("0x%lx", arg[i]); 1126*7c478bd9Sstevel@tonic-gate if (i < narg-1) { 1127*7c478bd9Sstevel@tonic-gate (void) fputc(',', stdout); 1128*7c478bd9Sstevel@tonic-gate (void) fputc(' ', stdout); 1129*7c478bd9Sstevel@tonic-gate } 1130*7c478bd9Sstevel@tonic-gate } 1131*7c478bd9Sstevel@tonic-gate (void) printf(")\n"); 1132*7c478bd9Sstevel@tonic-gate Flush(); 1133*7c478bd9Sstevel@tonic-gate } 1134*7c478bd9Sstevel@tonic-gate 1135*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 1136*7c478bd9Sstevel@tonic-gate void 1137*7c478bd9Sstevel@tonic-gate show_function_return(private_t *pri, long rval, int stret, 1138*7c478bd9Sstevel@tonic-gate struct callstack *Stk, struct dynlib *Dp, struct bkpt *Bp) 1139*7c478bd9Sstevel@tonic-gate { 1140*7c478bd9Sstevel@tonic-gate int i; 1141*7c478bd9Sstevel@tonic-gate 1142*7c478bd9Sstevel@tonic-gate make_pname(pri, Stk->tid); 1143*7c478bd9Sstevel@tonic-gate putpname(pri); 1144*7c478bd9Sstevel@tonic-gate timestamp(pri); 1145*7c478bd9Sstevel@tonic-gate for (i = 0; i < Stk->ncall; i++) { 1146*7c478bd9Sstevel@tonic-gate (void) fputc(' ', stdout); 1147*7c478bd9Sstevel@tonic-gate (void) fputc(' ', stdout); 1148*7c478bd9Sstevel@tonic-gate } 1149*7c478bd9Sstevel@tonic-gate (void) printf("<- %s%s() = ", Dp->prt_name, Bp->sym_name); 1150*7c478bd9Sstevel@tonic-gate if (stret) { 1151*7c478bd9Sstevel@tonic-gate (void) printf("struct return\n"); 1152*7c478bd9Sstevel@tonic-gate } else if (data_model == PR_MODEL_LP64) { 1153*7c478bd9Sstevel@tonic-gate if (rval >= (64 * 1024) || -rval >= (64 * 1024)) 1154*7c478bd9Sstevel@tonic-gate (void) printf("0x%lx\n", rval); 1155*7c478bd9Sstevel@tonic-gate else 1156*7c478bd9Sstevel@tonic-gate (void) printf("%ld\n", rval); 1157*7c478bd9Sstevel@tonic-gate } else { 1158*7c478bd9Sstevel@tonic-gate int rval32 = (int)rval; 1159*7c478bd9Sstevel@tonic-gate if (rval32 >= (64 * 1024) || -rval32 >= (64 * 1024)) 1160*7c478bd9Sstevel@tonic-gate (void) printf("0x%x\n", rval32); 1161*7c478bd9Sstevel@tonic-gate else 1162*7c478bd9Sstevel@tonic-gate (void) printf("%d\n", rval32); 1163*7c478bd9Sstevel@tonic-gate } 1164*7c478bd9Sstevel@tonic-gate Flush(); 1165*7c478bd9Sstevel@tonic-gate } 1166*7c478bd9Sstevel@tonic-gate 1167*7c478bd9Sstevel@tonic-gate /* 1168*7c478bd9Sstevel@tonic-gate * Called to deal with function-call tracing. 1169*7c478bd9Sstevel@tonic-gate * Return 0 on normal success, 1 to indicate a BPT_HANG success, 1170*7c478bd9Sstevel@tonic-gate * and -1 on failure (not tracing functions or unknown breakpoint). 1171*7c478bd9Sstevel@tonic-gate */ 1172*7c478bd9Sstevel@tonic-gate int 1173*7c478bd9Sstevel@tonic-gate function_trace(private_t *pri, int first, int clear, int dotrace) 1174*7c478bd9Sstevel@tonic-gate { 1175*7c478bd9Sstevel@tonic-gate struct ps_lwphandle *Lwp = pri->Lwp; 1176*7c478bd9Sstevel@tonic-gate const lwpstatus_t *Lsp = pri->lwpstat; 1177*7c478bd9Sstevel@tonic-gate uintptr_t pc = Lsp->pr_reg[R_PC]; 1178*7c478bd9Sstevel@tonic-gate uintptr_t sp = Lsp->pr_reg[R_SP]; 1179*7c478bd9Sstevel@tonic-gate uintptr_t fp = Lsp->pr_reg[R_FP]; 1180*7c478bd9Sstevel@tonic-gate struct bkpt *Bp; 1181*7c478bd9Sstevel@tonic-gate struct dynlib *Dp; 1182*7c478bd9Sstevel@tonic-gate struct callstack *Stk; 1183*7c478bd9Sstevel@tonic-gate ulong_t instr; 1184*7c478bd9Sstevel@tonic-gate int active; 1185*7c478bd9Sstevel@tonic-gate int rval = 0; 1186*7c478bd9Sstevel@tonic-gate 1187*7c478bd9Sstevel@tonic-gate if (Dynpat == NULL) 1188*7c478bd9Sstevel@tonic-gate return (-1); 1189*7c478bd9Sstevel@tonic-gate 1190*7c478bd9Sstevel@tonic-gate if (data_model != PR_MODEL_LP64) { 1191*7c478bd9Sstevel@tonic-gate pc = (uint32_t)pc; 1192*7c478bd9Sstevel@tonic-gate sp = (uint32_t)sp; 1193*7c478bd9Sstevel@tonic-gate fp = (uint32_t)fp; 1194*7c478bd9Sstevel@tonic-gate } 1195*7c478bd9Sstevel@tonic-gate 1196*7c478bd9Sstevel@tonic-gate if ((Bp = get_bkpt(pc)) == NULL) { 1197*7c478bd9Sstevel@tonic-gate if (hflag) 1198*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1199*7c478bd9Sstevel@tonic-gate "function_trace(): " 1200*7c478bd9Sstevel@tonic-gate "cannot find breakpoint for pc: 0x%.8lx\n", 1201*7c478bd9Sstevel@tonic-gate (ulong_t)pc); 1202*7c478bd9Sstevel@tonic-gate return (-1); 1203*7c478bd9Sstevel@tonic-gate } 1204*7c478bd9Sstevel@tonic-gate 1205*7c478bd9Sstevel@tonic-gate if ((Bp->flags & (BPT_PREINIT|BPT_POSTINIT|BPT_DLACTIVITY)) && !clear) { 1206*7c478bd9Sstevel@tonic-gate rd_event_msg_t event_msg; 1207*7c478bd9Sstevel@tonic-gate 1208*7c478bd9Sstevel@tonic-gate if (hflag) { 1209*7c478bd9Sstevel@tonic-gate if (Bp->flags & BPT_PREINIT) 1210*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "function_trace(): " 1211*7c478bd9Sstevel@tonic-gate "RD_PREINIT breakpoint\n"); 1212*7c478bd9Sstevel@tonic-gate if (Bp->flags & BPT_POSTINIT) 1213*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "function_trace(): " 1214*7c478bd9Sstevel@tonic-gate "RD_POSTINIT breakpoint\n"); 1215*7c478bd9Sstevel@tonic-gate if (Bp->flags & BPT_DLACTIVITY) 1216*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "function_trace(): " 1217*7c478bd9Sstevel@tonic-gate "RD_DLACTIVITY breakpoint\n"); 1218*7c478bd9Sstevel@tonic-gate } 1219*7c478bd9Sstevel@tonic-gate if (rd_event_getmsg(Rdb_agent, &event_msg) == RD_OK) { 1220*7c478bd9Sstevel@tonic-gate if (event_msg.type == RD_DLACTIVITY) { 1221*7c478bd9Sstevel@tonic-gate if (event_msg.u.state == RD_CONSISTENT) 1222*7c478bd9Sstevel@tonic-gate establish_breakpoints(); 1223*7c478bd9Sstevel@tonic-gate if (event_msg.u.state == RD_ADD) { 1224*7c478bd9Sstevel@tonic-gate if (hflag) 1225*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1226*7c478bd9Sstevel@tonic-gate "RD_DLACTIVITY/RD_ADD " 1227*7c478bd9Sstevel@tonic-gate "state reached\n"); 1228*7c478bd9Sstevel@tonic-gate not_consist = TRUE; /* kludge */ 1229*7c478bd9Sstevel@tonic-gate establish_breakpoints(); 1230*7c478bd9Sstevel@tonic-gate not_consist = FALSE; 1231*7c478bd9Sstevel@tonic-gate } 1232*7c478bd9Sstevel@tonic-gate } 1233*7c478bd9Sstevel@tonic-gate if (hflag) { 1234*7c478bd9Sstevel@tonic-gate const char *et; 1235*7c478bd9Sstevel@tonic-gate char buf[32]; 1236*7c478bd9Sstevel@tonic-gate 1237*7c478bd9Sstevel@tonic-gate switch (event_msg.type) { 1238*7c478bd9Sstevel@tonic-gate case RD_NONE: 1239*7c478bd9Sstevel@tonic-gate et = "RD_NONE"; 1240*7c478bd9Sstevel@tonic-gate break; 1241*7c478bd9Sstevel@tonic-gate case RD_PREINIT: 1242*7c478bd9Sstevel@tonic-gate et = "RD_PREINIT"; 1243*7c478bd9Sstevel@tonic-gate break; 1244*7c478bd9Sstevel@tonic-gate case RD_POSTINIT: 1245*7c478bd9Sstevel@tonic-gate et = "RD_POSTINIT"; 1246*7c478bd9Sstevel@tonic-gate break; 1247*7c478bd9Sstevel@tonic-gate case RD_DLACTIVITY: 1248*7c478bd9Sstevel@tonic-gate et = "RD_DLACTIVITY"; 1249*7c478bd9Sstevel@tonic-gate break; 1250*7c478bd9Sstevel@tonic-gate default: 1251*7c478bd9Sstevel@tonic-gate (void) sprintf(buf, "0x%x", 1252*7c478bd9Sstevel@tonic-gate event_msg.type); 1253*7c478bd9Sstevel@tonic-gate et = buf; 1254*7c478bd9Sstevel@tonic-gate break; 1255*7c478bd9Sstevel@tonic-gate } 1256*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1257*7c478bd9Sstevel@tonic-gate "event_msg.type = %s ", et); 1258*7c478bd9Sstevel@tonic-gate switch (event_msg.u.state) { 1259*7c478bd9Sstevel@tonic-gate case RD_NOSTATE: 1260*7c478bd9Sstevel@tonic-gate et = "RD_NOSTATE"; 1261*7c478bd9Sstevel@tonic-gate break; 1262*7c478bd9Sstevel@tonic-gate case RD_CONSISTENT: 1263*7c478bd9Sstevel@tonic-gate et = "RD_CONSISTENT"; 1264*7c478bd9Sstevel@tonic-gate break; 1265*7c478bd9Sstevel@tonic-gate case RD_ADD: 1266*7c478bd9Sstevel@tonic-gate et = "RD_ADD"; 1267*7c478bd9Sstevel@tonic-gate break; 1268*7c478bd9Sstevel@tonic-gate case RD_DELETE: 1269*7c478bd9Sstevel@tonic-gate et = "RD_DELETE"; 1270*7c478bd9Sstevel@tonic-gate break; 1271*7c478bd9Sstevel@tonic-gate default: 1272*7c478bd9Sstevel@tonic-gate (void) sprintf(buf, "0x%x", 1273*7c478bd9Sstevel@tonic-gate event_msg.u.state); 1274*7c478bd9Sstevel@tonic-gate et = buf; 1275*7c478bd9Sstevel@tonic-gate break; 1276*7c478bd9Sstevel@tonic-gate } 1277*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1278*7c478bd9Sstevel@tonic-gate "event_msg.u.state = %s\n", et); 1279*7c478bd9Sstevel@tonic-gate } 1280*7c478bd9Sstevel@tonic-gate } 1281*7c478bd9Sstevel@tonic-gate } 1282*7c478bd9Sstevel@tonic-gate 1283*7c478bd9Sstevel@tonic-gate if ((Bp->flags & BPT_TD_CREATE) && !clear) { 1284*7c478bd9Sstevel@tonic-gate nthr_create++; 1285*7c478bd9Sstevel@tonic-gate if (hflag) 1286*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "function_trace(): " 1287*7c478bd9Sstevel@tonic-gate "BPT_TD_CREATE breakpoint\n"); 1288*7c478bd9Sstevel@tonic-gate /* we don't care about the event message */ 1289*7c478bd9Sstevel@tonic-gate } 1290*7c478bd9Sstevel@tonic-gate 1291*7c478bd9Sstevel@tonic-gate Dp = Bp->dyn; 1292*7c478bd9Sstevel@tonic-gate 1293*7c478bd9Sstevel@tonic-gate if (dotrace) { 1294*7c478bd9Sstevel@tonic-gate if ((Stk = callstack_info(sp, fp, 1)) == NULL) { 1295*7c478bd9Sstevel@tonic-gate if (Dp != NULL && !clear) { 1296*7c478bd9Sstevel@tonic-gate if (cflag) { 1297*7c478bd9Sstevel@tonic-gate add_fcall(fcall_tbl, Dp->prt_name, 1298*7c478bd9Sstevel@tonic-gate Bp->sym_name, (unsigned long)1); 1299*7c478bd9Sstevel@tonic-gate } 1300*7c478bd9Sstevel@tonic-gate else 1301*7c478bd9Sstevel@tonic-gate show_function_call(pri, NULL, Dp, Bp); 1302*7c478bd9Sstevel@tonic-gate if ((Bp->flags & BPT_HANG) && !first) 1303*7c478bd9Sstevel@tonic-gate rval = 1; 1304*7c478bd9Sstevel@tonic-gate } 1305*7c478bd9Sstevel@tonic-gate } else if (!clear) { 1306*7c478bd9Sstevel@tonic-gate if (Dp != NULL) { 1307*7c478bd9Sstevel@tonic-gate function_entry(pri, Bp, Stk); 1308*7c478bd9Sstevel@tonic-gate if ((Bp->flags & BPT_HANG) && !first) 1309*7c478bd9Sstevel@tonic-gate rval = 1; 1310*7c478bd9Sstevel@tonic-gate } else { 1311*7c478bd9Sstevel@tonic-gate function_return(pri, Stk); 1312*7c478bd9Sstevel@tonic-gate } 1313*7c478bd9Sstevel@tonic-gate } 1314*7c478bd9Sstevel@tonic-gate } 1315*7c478bd9Sstevel@tonic-gate 1316*7c478bd9Sstevel@tonic-gate /* 1317*7c478bd9Sstevel@tonic-gate * Single-step the traced instruction. Since it's possible that 1318*7c478bd9Sstevel@tonic-gate * another thread has deactivated this breakpoint, we indicate 1319*7c478bd9Sstevel@tonic-gate * that we have reactivated it by virtue of executing it. 1320*7c478bd9Sstevel@tonic-gate * 1321*7c478bd9Sstevel@tonic-gate * To avoid a deadlock with some other thread in the process 1322*7c478bd9Sstevel@tonic-gate * performing a fork() or a thr_suspend() operation, we must 1323*7c478bd9Sstevel@tonic-gate * drop and later reacquire truss_lock. Some fancy dancing here. 1324*7c478bd9Sstevel@tonic-gate */ 1325*7c478bd9Sstevel@tonic-gate active = (Bp->flags & BPT_ACTIVE); 1326*7c478bd9Sstevel@tonic-gate Bp->flags |= BPT_ACTIVE; 1327*7c478bd9Sstevel@tonic-gate instr = Bp->instr; 1328*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(&truss_lock); 1329*7c478bd9Sstevel@tonic-gate (void) Lxecbkpt(Lwp, instr); 1330*7c478bd9Sstevel@tonic-gate (void) mutex_lock(&truss_lock); 1331*7c478bd9Sstevel@tonic-gate 1332*7c478bd9Sstevel@tonic-gate if (rval || clear) { /* leave process stopped and abandoned */ 1333*7c478bd9Sstevel@tonic-gate #if defined(__i386) 1334*7c478bd9Sstevel@tonic-gate /* 1335*7c478bd9Sstevel@tonic-gate * Leave it stopped in a state that a stack trace is reasonable. 1336*7c478bd9Sstevel@tonic-gate */ 1337*7c478bd9Sstevel@tonic-gate /* XX64 needs to be updated for amd64 & gcc */ 1338*7c478bd9Sstevel@tonic-gate if (rval && instr == 0x55) { /* pushl %ebp */ 1339*7c478bd9Sstevel@tonic-gate /* step it over the movl %esp,%ebp */ 1340*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(&truss_lock); 1341*7c478bd9Sstevel@tonic-gate (void) Lsetrun(Lwp, 0, PRCFAULT|PRSTEP); 1342*7c478bd9Sstevel@tonic-gate /* we're wrapping up; wait one second at most */ 1343*7c478bd9Sstevel@tonic-gate (void) Lwait(Lwp, MILLISEC); 1344*7c478bd9Sstevel@tonic-gate (void) mutex_lock(&truss_lock); 1345*7c478bd9Sstevel@tonic-gate } 1346*7c478bd9Sstevel@tonic-gate #endif 1347*7c478bd9Sstevel@tonic-gate if (get_bkpt(pc) != Bp) 1348*7c478bd9Sstevel@tonic-gate abend("function_trace: lost breakpoint", NULL); 1349*7c478bd9Sstevel@tonic-gate (void) Pdelbkpt(Proc, Bp->addr, Bp->instr); 1350*7c478bd9Sstevel@tonic-gate Bp->flags &= ~BPT_ACTIVE; 1351*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(&truss_lock); 1352*7c478bd9Sstevel@tonic-gate (void) Lsetrun(Lwp, 0, PRCFAULT|PRSTOP); 1353*7c478bd9Sstevel@tonic-gate /* we're wrapping up; wait one second at most */ 1354*7c478bd9Sstevel@tonic-gate (void) Lwait(Lwp, MILLISEC); 1355*7c478bd9Sstevel@tonic-gate (void) mutex_lock(&truss_lock); 1356*7c478bd9Sstevel@tonic-gate } else { 1357*7c478bd9Sstevel@tonic-gate if (get_bkpt(pc) != Bp) 1358*7c478bd9Sstevel@tonic-gate abend("function_trace: lost breakpoint", NULL); 1359*7c478bd9Sstevel@tonic-gate if (!active || !(Bp->flags & BPT_ACTIVE)) { 1360*7c478bd9Sstevel@tonic-gate (void) Pdelbkpt(Proc, Bp->addr, Bp->instr); 1361*7c478bd9Sstevel@tonic-gate Bp->flags &= ~BPT_ACTIVE; 1362*7c478bd9Sstevel@tonic-gate } 1363*7c478bd9Sstevel@tonic-gate } 1364*7c478bd9Sstevel@tonic-gate return (rval); 1365*7c478bd9Sstevel@tonic-gate } 1366*7c478bd9Sstevel@tonic-gate 1367*7c478bd9Sstevel@tonic-gate void 1368*7c478bd9Sstevel@tonic-gate function_entry(private_t *pri, struct bkpt *Bp, struct callstack *Stk) 1369*7c478bd9Sstevel@tonic-gate { 1370*7c478bd9Sstevel@tonic-gate const lwpstatus_t *Lsp = pri->lwpstat; 1371*7c478bd9Sstevel@tonic-gate uintptr_t sp = Lsp->pr_reg[R_SP]; 1372*7c478bd9Sstevel@tonic-gate uintptr_t rpc = get_return_address(&sp); 1373*7c478bd9Sstevel@tonic-gate struct dynlib *Dp = Bp->dyn; 1374*7c478bd9Sstevel@tonic-gate int oldframe = FALSE; 1375*7c478bd9Sstevel@tonic-gate int i; 1376*7c478bd9Sstevel@tonic-gate 1377*7c478bd9Sstevel@tonic-gate #ifdef _LP64 1378*7c478bd9Sstevel@tonic-gate if (data_model != PR_MODEL_LP64) { 1379*7c478bd9Sstevel@tonic-gate sp = (uint32_t)sp; 1380*7c478bd9Sstevel@tonic-gate rpc = (uint32_t)rpc; 1381*7c478bd9Sstevel@tonic-gate } 1382*7c478bd9Sstevel@tonic-gate #endif 1383*7c478bd9Sstevel@tonic-gate 1384*7c478bd9Sstevel@tonic-gate /* 1385*7c478bd9Sstevel@tonic-gate * If the sp is not within the stack bounds, forget it. 1386*7c478bd9Sstevel@tonic-gate * If the symbol's 'internal' flag is false, 1387*7c478bd9Sstevel@tonic-gate * don't report internal calls within the library. 1388*7c478bd9Sstevel@tonic-gate */ 1389*7c478bd9Sstevel@tonic-gate if (!(sp >= Stk->stkbase && sp < Stk->stkend) || 1390*7c478bd9Sstevel@tonic-gate (!(Bp->flags & BPT_INTERNAL) && 1391*7c478bd9Sstevel@tonic-gate rpc >= Dp->base && rpc < Dp->base + Dp->size)) 1392*7c478bd9Sstevel@tonic-gate return; 1393*7c478bd9Sstevel@tonic-gate 1394*7c478bd9Sstevel@tonic-gate for (i = 0; i < Stk->ncall; i++) { 1395*7c478bd9Sstevel@tonic-gate if (sp >= Stk->stack[i].sp) { 1396*7c478bd9Sstevel@tonic-gate Stk->ncall = i; 1397*7c478bd9Sstevel@tonic-gate if (sp == Stk->stack[i].sp) 1398*7c478bd9Sstevel@tonic-gate oldframe = TRUE; 1399*7c478bd9Sstevel@tonic-gate break; 1400*7c478bd9Sstevel@tonic-gate } 1401*7c478bd9Sstevel@tonic-gate } 1402*7c478bd9Sstevel@tonic-gate 1403*7c478bd9Sstevel@tonic-gate /* 1404*7c478bd9Sstevel@tonic-gate * Breakpoints for function returns are set here 1405*7c478bd9Sstevel@tonic-gate * If we're counting function calls, there is no need to set 1406*7c478bd9Sstevel@tonic-gate * a breakpoint upon return 1407*7c478bd9Sstevel@tonic-gate */ 1408*7c478bd9Sstevel@tonic-gate 1409*7c478bd9Sstevel@tonic-gate if (!oldframe && !cflag) { 1410*7c478bd9Sstevel@tonic-gate (void) create_bkpt(rpc, 1, 1); /* may or may not be set */ 1411*7c478bd9Sstevel@tonic-gate Stk->stack[Stk->ncall].sp = sp; /* record it anyeay */ 1412*7c478bd9Sstevel@tonic-gate Stk->stack[Stk->ncall].pc = rpc; 1413*7c478bd9Sstevel@tonic-gate Stk->stack[Stk->ncall].fcn = Bp; 1414*7c478bd9Sstevel@tonic-gate } 1415*7c478bd9Sstevel@tonic-gate Stk->ncall++; 1416*7c478bd9Sstevel@tonic-gate if (cflag) { 1417*7c478bd9Sstevel@tonic-gate add_fcall(fcall_tbl, Dp->prt_name, Bp->sym_name, 1418*7c478bd9Sstevel@tonic-gate (unsigned long)1); 1419*7c478bd9Sstevel@tonic-gate } else { 1420*7c478bd9Sstevel@tonic-gate show_function_call(pri, Stk, Dp, Bp); 1421*7c478bd9Sstevel@tonic-gate } 1422*7c478bd9Sstevel@tonic-gate } 1423*7c478bd9Sstevel@tonic-gate 1424*7c478bd9Sstevel@tonic-gate /* 1425*7c478bd9Sstevel@tonic-gate * We are here because we hit an unnamed breakpoint. 1426*7c478bd9Sstevel@tonic-gate * Attempt to match this up with a return pc on the stack 1427*7c478bd9Sstevel@tonic-gate * and report the function return. 1428*7c478bd9Sstevel@tonic-gate */ 1429*7c478bd9Sstevel@tonic-gate void 1430*7c478bd9Sstevel@tonic-gate function_return(private_t *pri, struct callstack *Stk) 1431*7c478bd9Sstevel@tonic-gate { 1432*7c478bd9Sstevel@tonic-gate const lwpstatus_t *Lsp = pri->lwpstat; 1433*7c478bd9Sstevel@tonic-gate uintptr_t sp = Lsp->pr_reg[R_SP]; 1434*7c478bd9Sstevel@tonic-gate uintptr_t fp = Lsp->pr_reg[R_FP]; 1435*7c478bd9Sstevel@tonic-gate int i; 1436*7c478bd9Sstevel@tonic-gate 1437*7c478bd9Sstevel@tonic-gate #ifdef _LP64 1438*7c478bd9Sstevel@tonic-gate if (data_model != PR_MODEL_LP64) { 1439*7c478bd9Sstevel@tonic-gate sp = (uint32_t)sp; 1440*7c478bd9Sstevel@tonic-gate fp = (uint32_t)fp; 1441*7c478bd9Sstevel@tonic-gate } 1442*7c478bd9Sstevel@tonic-gate #endif 1443*7c478bd9Sstevel@tonic-gate 1444*7c478bd9Sstevel@tonic-gate if (fp < sp + 8) 1445*7c478bd9Sstevel@tonic-gate fp = sp + 8; 1446*7c478bd9Sstevel@tonic-gate 1447*7c478bd9Sstevel@tonic-gate for (i = Stk->ncall - 1; i >= 0; i--) { 1448*7c478bd9Sstevel@tonic-gate if (sp <= Stk->stack[i].sp && fp > Stk->stack[i].sp) { 1449*7c478bd9Sstevel@tonic-gate Stk->ncall = i; 1450*7c478bd9Sstevel@tonic-gate break; 1451*7c478bd9Sstevel@tonic-gate } 1452*7c478bd9Sstevel@tonic-gate } 1453*7c478bd9Sstevel@tonic-gate 1454*7c478bd9Sstevel@tonic-gate #if defined(i386) || defined(__amd64) 1455*7c478bd9Sstevel@tonic-gate if (i < 0) { 1456*7c478bd9Sstevel@tonic-gate /* probably __mul64() or friends -- try harder */ 1457*7c478bd9Sstevel@tonic-gate int j; 1458*7c478bd9Sstevel@tonic-gate for (j = 0; i < 0 && j < 8; j++) { /* up to 8 args */ 1459*7c478bd9Sstevel@tonic-gate sp -= 4; 1460*7c478bd9Sstevel@tonic-gate for (i = Stk->ncall - 1; i >= 0; i--) { 1461*7c478bd9Sstevel@tonic-gate if (sp <= Stk->stack[i].sp && 1462*7c478bd9Sstevel@tonic-gate fp > Stk->stack[i].sp) { 1463*7c478bd9Sstevel@tonic-gate Stk->ncall = i; 1464*7c478bd9Sstevel@tonic-gate break; 1465*7c478bd9Sstevel@tonic-gate } 1466*7c478bd9Sstevel@tonic-gate } 1467*7c478bd9Sstevel@tonic-gate } 1468*7c478bd9Sstevel@tonic-gate } 1469*7c478bd9Sstevel@tonic-gate #endif 1470*7c478bd9Sstevel@tonic-gate 1471*7c478bd9Sstevel@tonic-gate if ((i >= 0) && (!cflag)) { 1472*7c478bd9Sstevel@tonic-gate show_function_return(pri, Lsp->pr_reg[R_R0], 0, 1473*7c478bd9Sstevel@tonic-gate Stk, Stk->stack[i].fcn->dyn, Stk->stack[i].fcn); 1474*7c478bd9Sstevel@tonic-gate } 1475*7c478bd9Sstevel@tonic-gate } 1476*7c478bd9Sstevel@tonic-gate 1477*7c478bd9Sstevel@tonic-gate #if defined(__sparc) 1478*7c478bd9Sstevel@tonic-gate #define FPADJUST 0 1479*7c478bd9Sstevel@tonic-gate #elif defined(__amd64) 1480*7c478bd9Sstevel@tonic-gate #define FPADJUST 8 1481*7c478bd9Sstevel@tonic-gate #elif defined(__i386) 1482*7c478bd9Sstevel@tonic-gate #define FPADJUST 4 1483*7c478bd9Sstevel@tonic-gate #endif 1484*7c478bd9Sstevel@tonic-gate 1485*7c478bd9Sstevel@tonic-gate void 1486*7c478bd9Sstevel@tonic-gate trap_one_stack(prgregset_t reg) 1487*7c478bd9Sstevel@tonic-gate { 1488*7c478bd9Sstevel@tonic-gate struct dynlib *Dp; 1489*7c478bd9Sstevel@tonic-gate struct bkpt *Bp; 1490*7c478bd9Sstevel@tonic-gate struct callstack *Stk; 1491*7c478bd9Sstevel@tonic-gate GElf_Sym sym; 1492*7c478bd9Sstevel@tonic-gate char sym_name[32]; 1493*7c478bd9Sstevel@tonic-gate uintptr_t sp = reg[R_SP]; 1494*7c478bd9Sstevel@tonic-gate uintptr_t pc = reg[R_PC]; 1495*7c478bd9Sstevel@tonic-gate uintptr_t fp; 1496*7c478bd9Sstevel@tonic-gate uintptr_t rpc; 1497*7c478bd9Sstevel@tonic-gate uint_t nframe = 0; 1498*7c478bd9Sstevel@tonic-gate uint_t maxframe = 8; 1499*7c478bd9Sstevel@tonic-gate struct { 1500*7c478bd9Sstevel@tonic-gate uintptr_t sp; /* %sp within called function */ 1501*7c478bd9Sstevel@tonic-gate uintptr_t pc; /* %pc within called function */ 1502*7c478bd9Sstevel@tonic-gate uintptr_t rsp; /* the return sp */ 1503*7c478bd9Sstevel@tonic-gate uintptr_t rpc; /* the return pc */ 1504*7c478bd9Sstevel@tonic-gate } *frame = my_malloc(maxframe * sizeof (*frame), NULL); 1505*7c478bd9Sstevel@tonic-gate 1506*7c478bd9Sstevel@tonic-gate /* 1507*7c478bd9Sstevel@tonic-gate * Gather stack frames bottom to top. 1508*7c478bd9Sstevel@tonic-gate */ 1509*7c478bd9Sstevel@tonic-gate while (sp != 0) { 1510*7c478bd9Sstevel@tonic-gate fp = sp; /* remember higest non-null sp */ 1511*7c478bd9Sstevel@tonic-gate frame[nframe].sp = sp; 1512*7c478bd9Sstevel@tonic-gate frame[nframe].pc = pc; 1513*7c478bd9Sstevel@tonic-gate sp = previous_fp(sp, &pc); 1514*7c478bd9Sstevel@tonic-gate frame[nframe].rsp = sp; 1515*7c478bd9Sstevel@tonic-gate frame[nframe].rpc = pc; 1516*7c478bd9Sstevel@tonic-gate if (++nframe == maxframe) { 1517*7c478bd9Sstevel@tonic-gate maxframe *= 2; 1518*7c478bd9Sstevel@tonic-gate frame = my_realloc(frame, maxframe * sizeof (*frame), 1519*7c478bd9Sstevel@tonic-gate NULL); 1520*7c478bd9Sstevel@tonic-gate } 1521*7c478bd9Sstevel@tonic-gate } 1522*7c478bd9Sstevel@tonic-gate 1523*7c478bd9Sstevel@tonic-gate /* 1524*7c478bd9Sstevel@tonic-gate * Scan for function return breakpoints top to bottom. 1525*7c478bd9Sstevel@tonic-gate */ 1526*7c478bd9Sstevel@tonic-gate while (nframe--) { 1527*7c478bd9Sstevel@tonic-gate /* lookup the called function in the symbol tables */ 1528*7c478bd9Sstevel@tonic-gate if (Plookup_by_addr(Proc, frame[nframe].pc, sym_name, 1529*7c478bd9Sstevel@tonic-gate sizeof (sym_name), &sym) != 0) 1530*7c478bd9Sstevel@tonic-gate continue; 1531*7c478bd9Sstevel@tonic-gate 1532*7c478bd9Sstevel@tonic-gate pc = sym.st_value; /* entry point of the function */ 1533*7c478bd9Sstevel@tonic-gate rpc = frame[nframe].rpc; /* caller's return pc */ 1534*7c478bd9Sstevel@tonic-gate 1535*7c478bd9Sstevel@tonic-gate /* lookup the function in the breakpoint table */ 1536*7c478bd9Sstevel@tonic-gate if ((Bp = get_bkpt(pc)) == NULL || (Dp = Bp->dyn) == NULL) 1537*7c478bd9Sstevel@tonic-gate continue; 1538*7c478bd9Sstevel@tonic-gate 1539*7c478bd9Sstevel@tonic-gate if (!(Bp->flags & BPT_INTERNAL) && 1540*7c478bd9Sstevel@tonic-gate rpc >= Dp->base && rpc < Dp->base + Dp->size) 1541*7c478bd9Sstevel@tonic-gate continue; 1542*7c478bd9Sstevel@tonic-gate 1543*7c478bd9Sstevel@tonic-gate sp = frame[nframe].rsp + FPADJUST; /* %sp at time of call */ 1544*7c478bd9Sstevel@tonic-gate if ((Stk = callstack_info(sp, fp, 0)) == NULL) 1545*7c478bd9Sstevel@tonic-gate continue; /* can't happen? */ 1546*7c478bd9Sstevel@tonic-gate 1547*7c478bd9Sstevel@tonic-gate if (create_bkpt(rpc, 1, 1) != NULL) { 1548*7c478bd9Sstevel@tonic-gate Stk->stack[Stk->ncall].sp = sp; 1549*7c478bd9Sstevel@tonic-gate Stk->stack[Stk->ncall].pc = rpc; 1550*7c478bd9Sstevel@tonic-gate Stk->stack[Stk->ncall].fcn = Bp; 1551*7c478bd9Sstevel@tonic-gate Stk->ncall++; 1552*7c478bd9Sstevel@tonic-gate } 1553*7c478bd9Sstevel@tonic-gate } 1554*7c478bd9Sstevel@tonic-gate 1555*7c478bd9Sstevel@tonic-gate free(frame); 1556*7c478bd9Sstevel@tonic-gate } 1557*7c478bd9Sstevel@tonic-gate 1558*7c478bd9Sstevel@tonic-gate int 1559*7c478bd9Sstevel@tonic-gate lwp_stack_traps(void *cd, const lwpstatus_t *Lsp) 1560*7c478bd9Sstevel@tonic-gate { 1561*7c478bd9Sstevel@tonic-gate ph_map_t *ph_map = (ph_map_t *)cd; 1562*7c478bd9Sstevel@tonic-gate prgregset_t reg; 1563*7c478bd9Sstevel@tonic-gate 1564*7c478bd9Sstevel@tonic-gate (void) memcpy(reg, Lsp->pr_reg, sizeof (prgregset_t)); 1565*7c478bd9Sstevel@tonic-gate make_lwp_stack(Lsp, ph_map->pmap, ph_map->nmap); 1566*7c478bd9Sstevel@tonic-gate trap_one_stack(reg); 1567*7c478bd9Sstevel@tonic-gate 1568*7c478bd9Sstevel@tonic-gate return (interrupt | sigusr1); 1569*7c478bd9Sstevel@tonic-gate } 1570*7c478bd9Sstevel@tonic-gate 1571*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 1572*7c478bd9Sstevel@tonic-gate int 1573*7c478bd9Sstevel@tonic-gate thr_stack_traps(const td_thrhandle_t *Thp, void *cd) 1574*7c478bd9Sstevel@tonic-gate { 1575*7c478bd9Sstevel@tonic-gate prgregset_t reg; 1576*7c478bd9Sstevel@tonic-gate 1577*7c478bd9Sstevel@tonic-gate /* 1578*7c478bd9Sstevel@tonic-gate * We have already dealt with all the lwps. 1579*7c478bd9Sstevel@tonic-gate * We only care about unbound threads here (TD_PARTIALREG). 1580*7c478bd9Sstevel@tonic-gate */ 1581*7c478bd9Sstevel@tonic-gate if (td_thr_getgregs(Thp, reg) != TD_PARTIALREG) 1582*7c478bd9Sstevel@tonic-gate return (0); 1583*7c478bd9Sstevel@tonic-gate 1584*7c478bd9Sstevel@tonic-gate make_thr_stack(Thp, reg); 1585*7c478bd9Sstevel@tonic-gate trap_one_stack(reg); 1586*7c478bd9Sstevel@tonic-gate 1587*7c478bd9Sstevel@tonic-gate return (interrupt | sigusr1); 1588*7c478bd9Sstevel@tonic-gate } 1589*7c478bd9Sstevel@tonic-gate 1590*7c478bd9Sstevel@tonic-gate #if defined(__sparc) 1591*7c478bd9Sstevel@tonic-gate 1592*7c478bd9Sstevel@tonic-gate uintptr_t 1593*7c478bd9Sstevel@tonic-gate previous_fp(uintptr_t sp, uintptr_t *rpc) 1594*7c478bd9Sstevel@tonic-gate { 1595*7c478bd9Sstevel@tonic-gate uintptr_t fp = 0; 1596*7c478bd9Sstevel@tonic-gate uintptr_t pc = 0; 1597*7c478bd9Sstevel@tonic-gate 1598*7c478bd9Sstevel@tonic-gate #ifdef _LP64 1599*7c478bd9Sstevel@tonic-gate if (data_model == PR_MODEL_LP64) { 1600*7c478bd9Sstevel@tonic-gate struct rwindow64 rwin; 1601*7c478bd9Sstevel@tonic-gate if (Pread(Proc, &rwin, sizeof (rwin), sp + STACK_BIAS) 1602*7c478bd9Sstevel@tonic-gate == sizeof (rwin)) { 1603*7c478bd9Sstevel@tonic-gate fp = (uintptr_t)rwin.rw_fp; 1604*7c478bd9Sstevel@tonic-gate pc = (uintptr_t)rwin.rw_rtn; 1605*7c478bd9Sstevel@tonic-gate } 1606*7c478bd9Sstevel@tonic-gate if (fp != 0 && 1607*7c478bd9Sstevel@tonic-gate Pread(Proc, &rwin, sizeof (rwin), fp + STACK_BIAS) 1608*7c478bd9Sstevel@tonic-gate != sizeof (rwin)) 1609*7c478bd9Sstevel@tonic-gate fp = pc = 0; 1610*7c478bd9Sstevel@tonic-gate } else { 1611*7c478bd9Sstevel@tonic-gate struct rwindow32 rwin; 1612*7c478bd9Sstevel@tonic-gate #else /* _LP64 */ 1613*7c478bd9Sstevel@tonic-gate struct rwindow rwin; 1614*7c478bd9Sstevel@tonic-gate #endif /* _LP64 */ 1615*7c478bd9Sstevel@tonic-gate if (Pread(Proc, &rwin, sizeof (rwin), sp) == sizeof (rwin)) { 1616*7c478bd9Sstevel@tonic-gate fp = (uint32_t)rwin.rw_fp; 1617*7c478bd9Sstevel@tonic-gate pc = (uint32_t)rwin.rw_rtn; 1618*7c478bd9Sstevel@tonic-gate } 1619*7c478bd9Sstevel@tonic-gate if (fp != 0 && 1620*7c478bd9Sstevel@tonic-gate Pread(Proc, &rwin, sizeof (rwin), fp) != sizeof (rwin)) 1621*7c478bd9Sstevel@tonic-gate fp = pc = 0; 1622*7c478bd9Sstevel@tonic-gate #ifdef _LP64 1623*7c478bd9Sstevel@tonic-gate } 1624*7c478bd9Sstevel@tonic-gate #endif 1625*7c478bd9Sstevel@tonic-gate if (rpc) 1626*7c478bd9Sstevel@tonic-gate *rpc = pc; 1627*7c478bd9Sstevel@tonic-gate return (fp); 1628*7c478bd9Sstevel@tonic-gate } 1629*7c478bd9Sstevel@tonic-gate 1630*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 1631*7c478bd9Sstevel@tonic-gate uintptr_t 1632*7c478bd9Sstevel@tonic-gate get_return_address(uintptr_t *psp) 1633*7c478bd9Sstevel@tonic-gate { 1634*7c478bd9Sstevel@tonic-gate instr_t inst; 1635*7c478bd9Sstevel@tonic-gate private_t *pri = get_private(); 1636*7c478bd9Sstevel@tonic-gate const lwpstatus_t *Lsp = pri->lwpstat; 1637*7c478bd9Sstevel@tonic-gate uintptr_t rpc; 1638*7c478bd9Sstevel@tonic-gate 1639*7c478bd9Sstevel@tonic-gate rpc = (uintptr_t)Lsp->pr_reg[R_O7] + 8; 1640*7c478bd9Sstevel@tonic-gate if (data_model != PR_MODEL_LP64) 1641*7c478bd9Sstevel@tonic-gate rpc = (uint32_t)rpc; 1642*7c478bd9Sstevel@tonic-gate 1643*7c478bd9Sstevel@tonic-gate /* check for structure return (bletch!) */ 1644*7c478bd9Sstevel@tonic-gate if (Pread(Proc, &inst, sizeof (inst), rpc) == sizeof (inst) && 1645*7c478bd9Sstevel@tonic-gate inst < 0x1000) 1646*7c478bd9Sstevel@tonic-gate rpc += sizeof (instr_t); 1647*7c478bd9Sstevel@tonic-gate 1648*7c478bd9Sstevel@tonic-gate return (rpc); 1649*7c478bd9Sstevel@tonic-gate } 1650*7c478bd9Sstevel@tonic-gate 1651*7c478bd9Sstevel@tonic-gate int 1652*7c478bd9Sstevel@tonic-gate get_arguments(long *argp) 1653*7c478bd9Sstevel@tonic-gate { 1654*7c478bd9Sstevel@tonic-gate private_t *pri = get_private(); 1655*7c478bd9Sstevel@tonic-gate const lwpstatus_t *Lsp = pri->lwpstat; 1656*7c478bd9Sstevel@tonic-gate int i; 1657*7c478bd9Sstevel@tonic-gate 1658*7c478bd9Sstevel@tonic-gate if (data_model != PR_MODEL_LP64) 1659*7c478bd9Sstevel@tonic-gate for (i = 0; i < 4; i++) 1660*7c478bd9Sstevel@tonic-gate argp[i] = (uint_t)Lsp->pr_reg[R_O0+i]; 1661*7c478bd9Sstevel@tonic-gate else 1662*7c478bd9Sstevel@tonic-gate for (i = 0; i < 4; i++) 1663*7c478bd9Sstevel@tonic-gate argp[i] = (long)Lsp->pr_reg[R_O0+i]; 1664*7c478bd9Sstevel@tonic-gate return (4); 1665*7c478bd9Sstevel@tonic-gate } 1666*7c478bd9Sstevel@tonic-gate 1667*7c478bd9Sstevel@tonic-gate #endif /* __sparc */ 1668*7c478bd9Sstevel@tonic-gate 1669*7c478bd9Sstevel@tonic-gate #if defined(__i386) || defined(__amd64) 1670*7c478bd9Sstevel@tonic-gate 1671*7c478bd9Sstevel@tonic-gate uintptr_t 1672*7c478bd9Sstevel@tonic-gate previous_fp(uintptr_t fp, uintptr_t *rpc) 1673*7c478bd9Sstevel@tonic-gate { 1674*7c478bd9Sstevel@tonic-gate uintptr_t frame[2]; 1675*7c478bd9Sstevel@tonic-gate uintptr_t trash[2]; 1676*7c478bd9Sstevel@tonic-gate 1677*7c478bd9Sstevel@tonic-gate if (Pread(Proc, frame, sizeof (frame), fp) != sizeof (frame) || 1678*7c478bd9Sstevel@tonic-gate (frame[0] != 0 && 1679*7c478bd9Sstevel@tonic-gate Pread(Proc, trash, sizeof (trash), frame[0]) != sizeof (trash))) 1680*7c478bd9Sstevel@tonic-gate frame[0] = frame[1] = 0; 1681*7c478bd9Sstevel@tonic-gate 1682*7c478bd9Sstevel@tonic-gate if (rpc) 1683*7c478bd9Sstevel@tonic-gate *rpc = frame[1]; 1684*7c478bd9Sstevel@tonic-gate return (frame[0]); 1685*7c478bd9Sstevel@tonic-gate } 1686*7c478bd9Sstevel@tonic-gate 1687*7c478bd9Sstevel@tonic-gate #endif 1688*7c478bd9Sstevel@tonic-gate 1689*7c478bd9Sstevel@tonic-gate #if defined(__amd64) || defined(__i386) 1690*7c478bd9Sstevel@tonic-gate 1691*7c478bd9Sstevel@tonic-gate /* 1692*7c478bd9Sstevel@tonic-gate * Examine the instruction at the return location of a function call 1693*7c478bd9Sstevel@tonic-gate * and return the byte count by which the stack is adjusted on return. 1694*7c478bd9Sstevel@tonic-gate * It the instruction at the return location is an addl, as expected, 1695*7c478bd9Sstevel@tonic-gate * then adjust the return pc by the size of that instruction so that 1696*7c478bd9Sstevel@tonic-gate * we will place the return breakpoint on the following instruction. 1697*7c478bd9Sstevel@tonic-gate * This allows programs that interrogate their own stacks and record 1698*7c478bd9Sstevel@tonic-gate * function calls and arguments to work correctly even while we interfere. 1699*7c478bd9Sstevel@tonic-gate * Return the count on success, -1 on failure. 1700*7c478bd9Sstevel@tonic-gate */ 1701*7c478bd9Sstevel@tonic-gate int 1702*7c478bd9Sstevel@tonic-gate return_count32(uint32_t *ppc) 1703*7c478bd9Sstevel@tonic-gate { 1704*7c478bd9Sstevel@tonic-gate uintptr_t pc = *ppc; 1705*7c478bd9Sstevel@tonic-gate struct bkpt *Bp; 1706*7c478bd9Sstevel@tonic-gate int count; 1707*7c478bd9Sstevel@tonic-gate uchar_t instr[6]; /* instruction at pc */ 1708*7c478bd9Sstevel@tonic-gate 1709*7c478bd9Sstevel@tonic-gate if ((count = Pread(Proc, instr, sizeof (instr), pc)) < 0) 1710*7c478bd9Sstevel@tonic-gate return (-1); 1711*7c478bd9Sstevel@tonic-gate 1712*7c478bd9Sstevel@tonic-gate /* find the replaced instruction at pc (if any) */ 1713*7c478bd9Sstevel@tonic-gate if ((Bp = get_bkpt(pc)) != NULL && (Bp->flags & BPT_ACTIVE)) 1714*7c478bd9Sstevel@tonic-gate instr[0] = (uchar_t)Bp->instr; 1715*7c478bd9Sstevel@tonic-gate 1716*7c478bd9Sstevel@tonic-gate if (count != sizeof (instr) && 1717*7c478bd9Sstevel@tonic-gate (count < 3 || instr[0] != 0x83)) 1718*7c478bd9Sstevel@tonic-gate return (-1); 1719*7c478bd9Sstevel@tonic-gate 1720*7c478bd9Sstevel@tonic-gate /* 1721*7c478bd9Sstevel@tonic-gate * A bit of disassembly of the instruction is required here. 1722*7c478bd9Sstevel@tonic-gate */ 1723*7c478bd9Sstevel@tonic-gate if (instr[1] != 0xc4) { /* not an addl mumble,%esp inctruction */ 1724*7c478bd9Sstevel@tonic-gate count = 0; 1725*7c478bd9Sstevel@tonic-gate } else if (instr[0] == 0x81) { /* count is a longword */ 1726*7c478bd9Sstevel@tonic-gate count = instr[2]+(instr[3]<<8)+(instr[4]<<16)+(instr[5]<<24); 1727*7c478bd9Sstevel@tonic-gate *ppc += 6; 1728*7c478bd9Sstevel@tonic-gate } else if (instr[0] == 0x83) { /* count is a byte */ 1729*7c478bd9Sstevel@tonic-gate count = instr[2]; 1730*7c478bd9Sstevel@tonic-gate *ppc += 3; 1731*7c478bd9Sstevel@tonic-gate } else { /* not an addl inctruction */ 1732*7c478bd9Sstevel@tonic-gate count = 0; 1733*7c478bd9Sstevel@tonic-gate } 1734*7c478bd9Sstevel@tonic-gate 1735*7c478bd9Sstevel@tonic-gate return (count); 1736*7c478bd9Sstevel@tonic-gate } 1737*7c478bd9Sstevel@tonic-gate 1738*7c478bd9Sstevel@tonic-gate uintptr_t 1739*7c478bd9Sstevel@tonic-gate get_return_address32(uintptr_t *psp) 1740*7c478bd9Sstevel@tonic-gate { 1741*7c478bd9Sstevel@tonic-gate uint32_t sp = *psp; 1742*7c478bd9Sstevel@tonic-gate uint32_t rpc; 1743*7c478bd9Sstevel@tonic-gate int count; 1744*7c478bd9Sstevel@tonic-gate 1745*7c478bd9Sstevel@tonic-gate *psp += 4; /* account for popping the stack on return */ 1746*7c478bd9Sstevel@tonic-gate if (Pread(Proc, &rpc, sizeof (rpc), sp) != sizeof (rpc)) 1747*7c478bd9Sstevel@tonic-gate return (0); 1748*7c478bd9Sstevel@tonic-gate if ((count = return_count32(&rpc)) < 0) 1749*7c478bd9Sstevel@tonic-gate count = 0; 1750*7c478bd9Sstevel@tonic-gate *psp += count; /* expected sp on return */ 1751*7c478bd9Sstevel@tonic-gate return (rpc); 1752*7c478bd9Sstevel@tonic-gate } 1753*7c478bd9Sstevel@tonic-gate 1754*7c478bd9Sstevel@tonic-gate uintptr_t 1755*7c478bd9Sstevel@tonic-gate get_return_address(uintptr_t *psp) 1756*7c478bd9Sstevel@tonic-gate { 1757*7c478bd9Sstevel@tonic-gate #ifdef _LP64 1758*7c478bd9Sstevel@tonic-gate uintptr_t rpc; 1759*7c478bd9Sstevel@tonic-gate uintptr_t sp = *psp; 1760*7c478bd9Sstevel@tonic-gate 1761*7c478bd9Sstevel@tonic-gate if (data_model == PR_MODEL_LP64) { 1762*7c478bd9Sstevel@tonic-gate if (Pread(Proc, &rpc, sizeof (rpc), sp) != sizeof (rpc)) 1763*7c478bd9Sstevel@tonic-gate return (0); 1764*7c478bd9Sstevel@tonic-gate /* 1765*7c478bd9Sstevel@tonic-gate * Ignore arguments pushed on the stack. See comments in 1766*7c478bd9Sstevel@tonic-gate * get_arguments(). 1767*7c478bd9Sstevel@tonic-gate */ 1768*7c478bd9Sstevel@tonic-gate return (rpc); 1769*7c478bd9Sstevel@tonic-gate } else 1770*7c478bd9Sstevel@tonic-gate #endif 1771*7c478bd9Sstevel@tonic-gate return (get_return_address32(psp)); 1772*7c478bd9Sstevel@tonic-gate } 1773*7c478bd9Sstevel@tonic-gate 1774*7c478bd9Sstevel@tonic-gate 1775*7c478bd9Sstevel@tonic-gate int 1776*7c478bd9Sstevel@tonic-gate get_arguments32(long *argp) 1777*7c478bd9Sstevel@tonic-gate { 1778*7c478bd9Sstevel@tonic-gate private_t *pri = get_private(); 1779*7c478bd9Sstevel@tonic-gate const lwpstatus_t *Lsp = pri->lwpstat; 1780*7c478bd9Sstevel@tonic-gate uint32_t frame[5]; /* return pc + 4 args */ 1781*7c478bd9Sstevel@tonic-gate int narg; 1782*7c478bd9Sstevel@tonic-gate int count; 1783*7c478bd9Sstevel@tonic-gate int i; 1784*7c478bd9Sstevel@tonic-gate 1785*7c478bd9Sstevel@tonic-gate narg = Pread(Proc, frame, sizeof (frame), 1786*7c478bd9Sstevel@tonic-gate (uintptr_t)Lsp->pr_reg[R_SP]); 1787*7c478bd9Sstevel@tonic-gate narg -= sizeof (greg32_t); 1788*7c478bd9Sstevel@tonic-gate if (narg <= 0) 1789*7c478bd9Sstevel@tonic-gate return (0); 1790*7c478bd9Sstevel@tonic-gate narg /= sizeof (greg32_t); /* no more than 4 */ 1791*7c478bd9Sstevel@tonic-gate 1792*7c478bd9Sstevel@tonic-gate /* 1793*7c478bd9Sstevel@tonic-gate * Given the return PC, determine the number of arguments. 1794*7c478bd9Sstevel@tonic-gate */ 1795*7c478bd9Sstevel@tonic-gate if ((count = return_count32(&frame[0])) < 0) 1796*7c478bd9Sstevel@tonic-gate narg = 0; 1797*7c478bd9Sstevel@tonic-gate else { 1798*7c478bd9Sstevel@tonic-gate count /= sizeof (greg32_t); 1799*7c478bd9Sstevel@tonic-gate if (narg > count) 1800*7c478bd9Sstevel@tonic-gate narg = count; 1801*7c478bd9Sstevel@tonic-gate } 1802*7c478bd9Sstevel@tonic-gate 1803*7c478bd9Sstevel@tonic-gate for (i = 0; i < narg; i++) 1804*7c478bd9Sstevel@tonic-gate argp[i] = (long)frame[i+1]; 1805*7c478bd9Sstevel@tonic-gate 1806*7c478bd9Sstevel@tonic-gate return (narg); 1807*7c478bd9Sstevel@tonic-gate } 1808*7c478bd9Sstevel@tonic-gate 1809*7c478bd9Sstevel@tonic-gate int 1810*7c478bd9Sstevel@tonic-gate get_arguments(long *argp) 1811*7c478bd9Sstevel@tonic-gate { 1812*7c478bd9Sstevel@tonic-gate #ifdef _LP64 1813*7c478bd9Sstevel@tonic-gate private_t *pri = get_private(); 1814*7c478bd9Sstevel@tonic-gate const lwpstatus_t *Lsp = pri->lwpstat; 1815*7c478bd9Sstevel@tonic-gate 1816*7c478bd9Sstevel@tonic-gate if (data_model == PR_MODEL_LP64) { 1817*7c478bd9Sstevel@tonic-gate /* 1818*7c478bd9Sstevel@tonic-gate * On amd64, we do not know how many arguments are passed to 1819*7c478bd9Sstevel@tonic-gate * each function. While it may be possible to detect if we 1820*7c478bd9Sstevel@tonic-gate * have more than 6 arguments, it is of marginal value. 1821*7c478bd9Sstevel@tonic-gate * Instead, assume that we always have 6 arguments, which are 1822*7c478bd9Sstevel@tonic-gate * passed via registers. 1823*7c478bd9Sstevel@tonic-gate */ 1824*7c478bd9Sstevel@tonic-gate argp[0] = Lsp->pr_reg[REG_RDI]; 1825*7c478bd9Sstevel@tonic-gate argp[1] = Lsp->pr_reg[REG_RSI]; 1826*7c478bd9Sstevel@tonic-gate argp[2] = Lsp->pr_reg[REG_RDX]; 1827*7c478bd9Sstevel@tonic-gate argp[3] = Lsp->pr_reg[REG_RCX]; 1828*7c478bd9Sstevel@tonic-gate argp[4] = Lsp->pr_reg[REG_R8]; 1829*7c478bd9Sstevel@tonic-gate argp[5] = Lsp->pr_reg[REG_R9]; 1830*7c478bd9Sstevel@tonic-gate return (6); 1831*7c478bd9Sstevel@tonic-gate } else 1832*7c478bd9Sstevel@tonic-gate #endif 1833*7c478bd9Sstevel@tonic-gate return (get_arguments32(argp)); 1834*7c478bd9Sstevel@tonic-gate } 1835*7c478bd9Sstevel@tonic-gate 1836*7c478bd9Sstevel@tonic-gate #endif /* __amd64 || __i386 */ 1837