17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 580ab886dSwesolows * Common Development and Distribution License (the "License"). 680ab886dSwesolows * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 21d9638e54Smws 227c478bd9Sstevel@tonic-gate /* 2380ab886dSwesolows * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate #include <sys/types.h> 287c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 297c478bd9Sstevel@tonic-gate 307c478bd9Sstevel@tonic-gate #include <ucontext.h> 317c478bd9Sstevel@tonic-gate #include <strings.h> 327c478bd9Sstevel@tonic-gate #include <stdio.h> 337c478bd9Sstevel@tonic-gate #include <errno.h> 347c478bd9Sstevel@tonic-gate 357c478bd9Sstevel@tonic-gate #include <fmd_trace.h> 367c478bd9Sstevel@tonic-gate #include <fmd_alloc.h> 377c478bd9Sstevel@tonic-gate #include <fmd_subr.h> 387c478bd9Sstevel@tonic-gate #include <fmd_conf.h> 397c478bd9Sstevel@tonic-gate #include <fmd.h> 407c478bd9Sstevel@tonic-gate 417c478bd9Sstevel@tonic-gate fmd_tracebuf_t * 427c478bd9Sstevel@tonic-gate fmd_trace_create(void) 437c478bd9Sstevel@tonic-gate { 447c478bd9Sstevel@tonic-gate fmd_tracebuf_t *tbp = fmd_zalloc(sizeof (fmd_tracebuf_t), FMD_SLEEP); 457c478bd9Sstevel@tonic-gate size_t bufsize; 467c478bd9Sstevel@tonic-gate 477c478bd9Sstevel@tonic-gate (void) fmd_conf_getprop(fmd.d_conf, "trace.frames", &tbp->tb_frames); 487c478bd9Sstevel@tonic-gate (void) fmd_conf_getprop(fmd.d_conf, "trace.recs", &tbp->tb_recs); 497c478bd9Sstevel@tonic-gate 507c478bd9Sstevel@tonic-gate /* 517c478bd9Sstevel@tonic-gate * We require 8-byte alignment of fmd_tracerec_t to store hrtime_t's. 527c478bd9Sstevel@tonic-gate * Since the trailing flexible array member is of type uintptr_t, we 5380ab886dSwesolows * may need to allocate an additional element if we are compiling 5480ab886dSwesolows * 32-bit; otherwise uintptr_t is 8 bytes so any value of tb_frames is 5580ab886dSwesolows * acceptable. 5680ab886dSwesolows * 5780ab886dSwesolows * tb_frames includes the first element, whose size is reflected in 5880ab886dSwesolows * sizeof (fmd_tracerec_t). Therefore, if fmd_tracerec_t's size is 5980ab886dSwesolows * 0 mod 8, we must be sure the total number of frames is odd. 6080ab886dSwesolows * Otherwise, we need at least one extra frame, so the total count 6180ab886dSwesolows * must be even. This will continue to work even if the sizes or 6280ab886dSwesolows * types of other fmd_tracerec_t members are changed. 637c478bd9Sstevel@tonic-gate */ 647c478bd9Sstevel@tonic-gate #ifdef _ILP32 6580ab886dSwesolows /*CONSTCOND*/ 6680ab886dSwesolows if (sizeof (fmd_tracerec_t) % sizeof (hrtime_t) == 0) 6780ab886dSwesolows tbp->tb_frames = (tbp->tb_frames & ~1UL) + 1; 6880ab886dSwesolows else 697c478bd9Sstevel@tonic-gate tbp->tb_frames = P2ROUNDUP(tbp->tb_frames, 2); 707c478bd9Sstevel@tonic-gate #endif 717c478bd9Sstevel@tonic-gate tbp->tb_size = sizeof (fmd_tracerec_t) + 727c478bd9Sstevel@tonic-gate sizeof (uintptr_t) * (MAX(tbp->tb_frames, 1) - 1); 737c478bd9Sstevel@tonic-gate 747c478bd9Sstevel@tonic-gate bufsize = tbp->tb_size * tbp->tb_recs; 757c478bd9Sstevel@tonic-gate 767c478bd9Sstevel@tonic-gate tbp->tb_buf = fmd_zalloc(bufsize, FMD_SLEEP); 777c478bd9Sstevel@tonic-gate tbp->tb_end = (void *)((uintptr_t)tbp->tb_buf + bufsize - tbp->tb_size); 787c478bd9Sstevel@tonic-gate tbp->tb_ptr = tbp->tb_buf; 797c478bd9Sstevel@tonic-gate 807c478bd9Sstevel@tonic-gate return (tbp); 817c478bd9Sstevel@tonic-gate } 827c478bd9Sstevel@tonic-gate 837c478bd9Sstevel@tonic-gate void 847c478bd9Sstevel@tonic-gate fmd_trace_destroy(fmd_tracebuf_t *tbp) 857c478bd9Sstevel@tonic-gate { 867c478bd9Sstevel@tonic-gate fmd_free(tbp->tb_buf, tbp->tb_size * tbp->tb_recs); 877c478bd9Sstevel@tonic-gate fmd_free(tbp, sizeof (fmd_tracebuf_t)); 887c478bd9Sstevel@tonic-gate } 897c478bd9Sstevel@tonic-gate 907c478bd9Sstevel@tonic-gate /* 917c478bd9Sstevel@tonic-gate * Callback for walkcontext(3C) to store the stack trace. We use tr_tag below 927c478bd9Sstevel@tonic-gate * to store the maximum value of depth that is permitted so we can use it here. 937c478bd9Sstevel@tonic-gate */ 947c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 957c478bd9Sstevel@tonic-gate static int 967c478bd9Sstevel@tonic-gate fmd_trace_frame(uintptr_t pc, int sig, fmd_tracerec_t *trp) 977c478bd9Sstevel@tonic-gate { 987c478bd9Sstevel@tonic-gate trp->tr_stack[trp->tr_depth++] = pc; 997c478bd9Sstevel@tonic-gate return (trp->tr_depth >= trp->tr_tag); 1007c478bd9Sstevel@tonic-gate } 1017c478bd9Sstevel@tonic-gate 1027c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1037c478bd9Sstevel@tonic-gate fmd_tracerec_t * 104d9638e54Smws fmd_trace_none(fmd_tracebuf_t *tbp, uint_t tag, const char *format, va_list ap) 1057c478bd9Sstevel@tonic-gate { 1067c478bd9Sstevel@tonic-gate return (NULL); 1077c478bd9Sstevel@tonic-gate } 1087c478bd9Sstevel@tonic-gate 1097c478bd9Sstevel@tonic-gate fmd_tracerec_t * 110d9638e54Smws fmd_trace_lite(fmd_tracebuf_t *tbp, uint_t tag, const char *format, va_list ap) 1117c478bd9Sstevel@tonic-gate { 1127c478bd9Sstevel@tonic-gate hrtime_t time = gethrtime(); 1137c478bd9Sstevel@tonic-gate fmd_tracerec_t *trp = tbp->tb_ptr; 1147c478bd9Sstevel@tonic-gate char *p; 1157c478bd9Sstevel@tonic-gate 116d9638e54Smws if (tbp->tb_depth++ != 0) { 117d9638e54Smws tbp->tb_depth--; 118d9638e54Smws return (NULL); 119d9638e54Smws } 120d9638e54Smws 1217c478bd9Sstevel@tonic-gate trp->tr_time = time; 1227c478bd9Sstevel@tonic-gate trp->tr_file = NULL; 1237c478bd9Sstevel@tonic-gate trp->tr_line = 0; 1247c478bd9Sstevel@tonic-gate trp->tr_errno = (tag == FMD_DBG_ERR) ? errno : 0; 125d9638e54Smws trp->tr_tag = fmd_ntz32(tag); 1267c478bd9Sstevel@tonic-gate 1277c478bd9Sstevel@tonic-gate (void) vsnprintf(trp->tr_msg, sizeof (trp->tr_msg), format, ap); 1287c478bd9Sstevel@tonic-gate p = &trp->tr_msg[strlen(trp->tr_msg)]; 1297c478bd9Sstevel@tonic-gate if (p > trp->tr_msg && p[-1] == '\n') 1307c478bd9Sstevel@tonic-gate p[-1] = '\0'; 1317c478bd9Sstevel@tonic-gate 1327c478bd9Sstevel@tonic-gate if (tbp->tb_ptr != tbp->tb_end) 1337c478bd9Sstevel@tonic-gate tbp->tb_ptr = (void *)((uintptr_t)tbp->tb_ptr + tbp->tb_size); 1347c478bd9Sstevel@tonic-gate else 1357c478bd9Sstevel@tonic-gate tbp->tb_ptr = tbp->tb_buf; 1367c478bd9Sstevel@tonic-gate 137d9638e54Smws tbp->tb_depth--; 1387c478bd9Sstevel@tonic-gate return (trp); 1397c478bd9Sstevel@tonic-gate } 1407c478bd9Sstevel@tonic-gate 1417c478bd9Sstevel@tonic-gate fmd_tracerec_t * 142d9638e54Smws fmd_trace_full(fmd_tracebuf_t *tbp, uint_t tag, const char *format, va_list ap) 1437c478bd9Sstevel@tonic-gate { 1447c478bd9Sstevel@tonic-gate hrtime_t time = gethrtime(); 1457c478bd9Sstevel@tonic-gate fmd_tracerec_t *trp = tbp->tb_ptr; 1467c478bd9Sstevel@tonic-gate ucontext_t uc; 1477c478bd9Sstevel@tonic-gate char *p; 1487c478bd9Sstevel@tonic-gate 149d9638e54Smws if (tbp->tb_depth++ != 0) { 150d9638e54Smws tbp->tb_depth--; 151d9638e54Smws return (NULL); 152d9638e54Smws } 153d9638e54Smws 1547c478bd9Sstevel@tonic-gate (void) getcontext(&uc); 155*ce926fbbSZhiwen Zheng trp->tr_depth = 0; 1567c478bd9Sstevel@tonic-gate trp->tr_tag = tbp->tb_frames; /* for use by fmd_trace_frame() */ 1577c478bd9Sstevel@tonic-gate (void) walkcontext(&uc, (int (*)())fmd_trace_frame, trp); 1587c478bd9Sstevel@tonic-gate 1597c478bd9Sstevel@tonic-gate trp->tr_time = time; 1607c478bd9Sstevel@tonic-gate trp->tr_file = NULL; 1617c478bd9Sstevel@tonic-gate trp->tr_line = 0; 1627c478bd9Sstevel@tonic-gate trp->tr_errno = (tag == FMD_DBG_ERR) ? errno : 0; 163d9638e54Smws trp->tr_tag = fmd_ntz32(tag); 164d9638e54Smws 165d9638e54Smws if (fmd.d_fmd_debug & FMD_DBG_TRACE) 166d9638e54Smws fmd_vdprintf(tag, format, ap); 1677c478bd9Sstevel@tonic-gate 1687c478bd9Sstevel@tonic-gate (void) vsnprintf(trp->tr_msg, sizeof (trp->tr_msg), format, ap); 1697c478bd9Sstevel@tonic-gate p = &trp->tr_msg[strlen(trp->tr_msg)]; 1707c478bd9Sstevel@tonic-gate if (p > trp->tr_msg && p[-1] == '\n') 1717c478bd9Sstevel@tonic-gate p[-1] = '\0'; 1727c478bd9Sstevel@tonic-gate 1737c478bd9Sstevel@tonic-gate if (tbp->tb_ptr != tbp->tb_end) 1747c478bd9Sstevel@tonic-gate tbp->tb_ptr = (void *)((uintptr_t)tbp->tb_ptr + tbp->tb_size); 1757c478bd9Sstevel@tonic-gate else 1767c478bd9Sstevel@tonic-gate tbp->tb_ptr = tbp->tb_buf; 1777c478bd9Sstevel@tonic-gate 178d9638e54Smws tbp->tb_depth--; 1797c478bd9Sstevel@tonic-gate return (trp); 1807c478bd9Sstevel@tonic-gate } 181