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