📄 dt_consume.c
字号:
/* * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only. * See the file usr/src/LICENSING.NOTICE in this distribution or * http://www.opensolaris.org/license/ for details. */#pragma ident "@(#)dt_consume.c 1.15 04/12/18 SMI"#include <stdlib.h>#include <strings.h>#include <errno.h>#include <unistd.h>#include <limits.h>#include <assert.h>#include <ctype.h>#include <alloca.h>#include <dt_impl.h>static intdt_flowindent(dtrace_hdl_t *dtp, dtrace_probedata_t *data, dtrace_epid_t last, dtrace_bufdesc_t *buf, size_t offs){ dtrace_probedesc_t *pd = data->dtpda_pdesc, *npd; dtrace_eprobedesc_t *epd = data->dtpda_edesc, *nepd; char *p = pd->dtpd_provider, *n = pd->dtpd_name; dtrace_flowkind_t flow = DTRACEFLOW_NONE; const char *str = NULL; static const char *e_str[2] = { " -> ", " => " }; static const char *r_str[2] = { " <- ", " <= " }; dtrace_epid_t next, id = epd->dtepd_epid; int rval; if (strcmp(n, "entry") == 0) { flow = DTRACEFLOW_ENTRY; str = e_str[strcmp(p, "syscall") == 0]; } else if (strcmp(n, "return") == 0 || strcmp(n, "exit") == 0) { flow = DTRACEFLOW_RETURN; str = r_str[strcmp(p, "syscall") == 0]; } /* * If we're going to indent this, we need to check the ID of our last * call. If we're looking at the same probe ID but a different EPID, * we _don't_ want to indent. (Yes, there are some minor holes in * this scheme -- it's a heuristic.) */ if (flow == DTRACEFLOW_ENTRY) { if ((last != DTRACE_EPIDNONE && id != last && pd->dtpd_id == dtp->dt_pdesc[last]->dtpd_id)) flow = DTRACEFLOW_NONE; } /* * If we're going to unindent this, it's more difficult to see if * we don't actually want to unindent it -- we need to look at the * _next_ EPID. */ if (flow == DTRACEFLOW_RETURN) { offs += epd->dtepd_size; do { if (offs >= buf->dtbd_size) { /* * We're at the end -- maybe. If the oldest * record is non-zero, we need to wrap. */ if (buf->dtbd_oldest != 0) { offs = 0; } else { goto out; } } next = *(uint32_t *)((uintptr_t)buf->dtbd_data + offs); if (next == DTRACE_EPIDNONE) offs += sizeof (id); } while (next == DTRACE_EPIDNONE); if ((rval = dt_epid_lookup(dtp, next, &nepd, &npd)) != 0) return (rval); if (next != id && npd->dtpd_id == pd->dtpd_id) flow = DTRACEFLOW_NONE; }out: if (flow == DTRACEFLOW_ENTRY || flow == DTRACEFLOW_RETURN) { data->dtpda_prefix = str; } else { data->dtpda_prefix = "| "; } if (flow == DTRACEFLOW_RETURN && data->dtpda_indent > 0) data->dtpda_indent -= 2; data->dtpda_flow = flow; return (0);}static intdt_nullprobe(){ return (DTRACE_CONSUME_THIS);}static intdt_nullrec(){ return (DTRACE_CONSUME_NEXT);}intdt_print_quantize(dtrace_hdl_t *dtp, FILE *fp, const void *addr, size_t size, uint64_t normal){ const uint64_t *data = addr; int i, first_bin = 0, last_bin = DTRACE_QUANTIZE_NBUCKETS - 1; uint64_t total_bin_count = 0; if (size != DTRACE_QUANTIZE_NBUCKETS * sizeof (uint64_t)) return (dt_set_errno(dtp, EDT_DMISMATCH)); while (first_bin < DTRACE_QUANTIZE_NBUCKETS - 1 && data[first_bin] == 0) first_bin++; if (first_bin > 0) first_bin--; while (last_bin > 0 && data[last_bin] == 0) last_bin--; if (last_bin < DTRACE_QUANTIZE_NBUCKETS - 1) last_bin++; for (i = first_bin; i <= last_bin; i++) total_bin_count += data[i]; if (dt_printf(dtp, fp, "\n%16s %41s %-9s\n", "value", "------------- Distribution -------------", "count") < 0) return (-1); for (i = first_bin; i <= last_bin; i++) { float f = ((float)data[i] * 40.0) / (float)total_bin_count; uint_t depth = (uint_t)(f + 0.5); if (dt_printf(dtp, fp, "%16lld |%s%s %-9llu\n", (long long)DTRACE_QUANTIZE_BUCKETVAL(i), "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@" + 40 - depth, " " + depth, (u_longlong_t)data[i] / normal) < 0) return (-1); } return (0);}intdt_print_lquantize(dtrace_hdl_t *dtp, FILE *fp, const void *addr, size_t size, uint64_t normal){ const uint64_t *data = addr; int i, first_bin, last_bin, base; uint64_t arg, total_bin_count = 0; uint16_t step, levels; if (size < sizeof (uint64_t)) return (dt_set_errno(dtp, EDT_DMISMATCH)); arg = *data++; size -= sizeof (uint64_t); base = DTRACE_LQUANTIZE_BASE(arg); step = DTRACE_LQUANTIZE_STEP(arg); levels = DTRACE_LQUANTIZE_LEVELS(arg); first_bin = 0; last_bin = levels + 1; if (size != sizeof (uint64_t) * (levels + 2)) return (dt_set_errno(dtp, EDT_DMISMATCH)); while (first_bin < levels + 1 && data[first_bin] == 0) first_bin++; if (first_bin > 0) first_bin--; while (last_bin > 0 && data[last_bin] == 0) last_bin--; if (last_bin < levels + 1) last_bin++; for (i = first_bin; i <= last_bin; i++) total_bin_count += data[i]; if (dt_printf(dtp, fp, "\n%16s %41s %-9s\n", "value", "------------- Distribution -------------", "count") < 0) return (-1); for (i = first_bin; i <= last_bin; i++) { float f = ((float)data[i] * 40.0) / (float)total_bin_count; uint_t depth = (uint_t)(f + 0.5); char c[32]; int err; if (i == 0) { (void) snprintf(c, sizeof (c), "< %d", base / (uint32_t)normal); err = dt_printf(dtp, fp, "%16s ", c); } else if (i == levels + 1) { (void) snprintf(c, sizeof (c), ">= %d", base + (levels * step)); err = dt_printf(dtp, fp, "%16s ", c); } else { err = dt_printf(dtp, fp, "%16d ", base + (i - 1) * step); } if (err < 0 || dt_printf(dtp, fp, "|%s%s %-9llu\n", "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@" + 40 - depth, " " + depth, (u_longlong_t)data[i] / normal) < 0) return (-1); } return (0);}/*ARGSUSED*/static intdt_print_average(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr, size_t size, uint64_t normal){ /* LINTED - alignment */ uint64_t *data = (uint64_t *)addr; return (dt_printf(dtp, fp, " %16lld", data[0] ? (long long)(data[1] / normal / data[0]) : 0));}/*ARGSUSED*/intdt_print_bytes(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr, size_t nbytes, int width, int quiet){ /* * If the byte stream is a series of printable characters, followed by * a terminating byte, we print it out as a string. Otherwise, we * assume that it's something else and just print the bytes. */ int i, j, margin = 5; char *c = (char *)addr; if (nbytes == 0) return (0); if (dtp->dt_options[DTRACEOPT_RAWBYTES] != DTRACEOPT_UNSET) goto raw; for (i = 0; i < nbytes; i++) { /* * We define a "printable character" to be one for which * isprint(3C) returns non-zero, isspace(3C) returns non-zero, * or a character which is either backspace or the bell. * Backspace and the bell are regrettably special because * they fail the first two tests -- and yet they are entirely * printable. These are the only two control characters that * have meaning for the terminal and for which isprint(3C) and * isspace(3C) return 0. */ if (isprint(c[i]) || isspace(c[i]) || c[i] == '\b' || c[i] == '\a') continue; if (c[i] == '\0' && i > 0) { /* * This looks like it might be a string. Before we * assume that it is indeed a string, check the * remainder of the byte range; if it contains * additional non-nul characters, we'll assume that * it's a binary stream that just happens to look like * a string, and we'll print out the individual bytes. */ for (j = i + 1; j < nbytes; j++) { if (c[j] != '\0') break; } if (j != nbytes) break; if (quiet) return (dt_printf(dtp, fp, "%s", c)); else return (dt_printf(dtp, fp, " %-*s", width, c)); } break; } if (i == nbytes) { /* * The byte range is all printable characters, but there is * no trailing nul byte. We'll assume that it's a string and * print it as such. */ char *s = alloca(nbytes + 1); bcopy(c, s, nbytes); s[nbytes] = '\0'; return (dt_printf(dtp, fp, " %-*s", width, s)); }raw: if (dt_printf(dtp, fp, "\n%*s ", margin, "") < 0) return (-1); for (i = 0; i < 16; i++) if (dt_printf(dtp, fp, " %c", "0123456789abcdef"[i]) < 0) return (-1); if (dt_printf(dtp, fp, " 0123456789abcdef\n") < 0) return (-1); for (i = 0; i < nbytes; i += 16) { if (dt_printf(dtp, fp, "%*s%5x:", margin, "", i) < 0) return (-1); for (j = i; j < i + 16 && j < nbytes; j++) { if (dt_printf(dtp, fp, " %02x", (uchar_t)c[j]) < 0) return (-1); } while (j++ % 16) { if (dt_printf(dtp, fp, " ") < 0) return (-1); } if (dt_printf(dtp, fp, " ") < 0) return (-1); for (j = i; j < i + 16 && j < nbytes; j++) { if (dt_printf(dtp, fp, "%c", c[j] < ' ' || c[j] > '~' ? '.' : c[j]) < 0) return (-1); } if (dt_printf(dtp, fp, "\n") < 0) return (-1); } return (0);}intdt_print_stack(dtrace_hdl_t *dtp, FILE *fp, const char *format, caddr_t addr, int depth){ pc_t *pc = (pc_t *)(uintptr_t)addr; dtrace_syminfo_t dts; GElf_Sym sym; int i, indent; char c[PATH_MAX * 2]; if (dt_printf(dtp, fp, "\n") < 0) return (-1); if (format == NULL) format = "%s"; if (dtp->dt_options[DTRACEOPT_STACKINDENT] != DTRACEOPT_UNSET) indent = (int)dtp->dt_options[DTRACEOPT_STACKINDENT]; else indent = _dtrace_stkindent; for (i = 0; i < depth && pc[i] != NULL; i++) { if (dt_printf(dtp, fp, "%*s", indent, "") < 0) return (-1); if (dtrace_lookup_by_addr(dtp, pc[i], &sym, &dts) == 0) { if (pc[i] > sym.st_value) { (void) snprintf(c, sizeof (c), "%s`%s+0x%llx", dts.dts_object, dts.dts_name, (u_longlong_t)pc[i] - sym.st_value); } else { (void) snprintf(c, sizeof (c), "%s`%s", dts.dts_object, dts.dts_name); } } else { /* * We'll repeat the lookup, but this time we'll specify * a NULL GElf_Sym -- indicating that we're only * interested in the containing module. */ if (dtrace_lookup_by_addr(dtp, pc[i], NULL, &dts) == 0) { (void) snprintf(c, sizeof (c), "%s`0x%llx", dts.dts_object, (u_longlong_t)pc[i]); } else { (void) snprintf(c, sizeof (c), "0x%llx", (u_longlong_t)pc[i]); } } if (dt_printf(dtp, fp, format, c) < 0) return (-1); if (dt_printf(dtp, fp, "\n") < 0) return (-1); } return (0);}intdt_print_ustack(dtrace_hdl_t *dtp, FILE *fp, const char *format, caddr_t addr, uint64_t arg){ uint64_t *pc = (uint64_t *)(uintptr_t)addr; uint32_t depth = DTRACE_USTACK_NFRAMES(arg); uint32_t strsize = DTRACE_USTACK_STRSIZE(arg); const char *strbase = addr + (depth + 1) * sizeof (uint64_t); const char *str = strsize ? strbase : NULL; int err = 0; char name[PATH_MAX], objname[PATH_MAX], c[PATH_MAX * 2]; struct ps_prochandle *P; GElf_Sym sym; int i, indent; pid_t pid; if (depth == 0) return (0); pid = (pid_t)*pc++; if (dt_printf(dtp, fp, "\n") < 0) return (-1); if (format == NULL) format = "%s"; if (dtp->dt_options[DTRACEOPT_STACKINDENT] != DTRACEOPT_UNSET) indent = (int)dtp->dt_options[DTRACEOPT_STACKINDENT]; else indent = _dtrace_stkindent; /* * Ultimately, we need to add an entry point in the library vector for * determining <symbol, offset> from <pid, address>. For now, if * this is a vector open, we just print the raw address or string. */ if (dtp->dt_vector == NULL) P = dt_proc_grab(dtp, pid, PGRAB_RDONLY | PGRAB_FORCE, 0); else P = NULL; if (P != NULL) dt_proc_lock(dtp, P); /* lock handle while we perform lookups */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -