xref: /dragonfly/usr.bin/systat/symbols.c (revision 91dc43dd)
14d983f79SMatthew Dillon /*
24d983f79SMatthew Dillon  * Copyright (c) 2010 The DragonFly Project.  All rights reserved.
34d983f79SMatthew Dillon  *
44d983f79SMatthew Dillon  * This code is derived from software contributed to The DragonFly Project
54d983f79SMatthew Dillon  * by Matthew Dillon <dillon@backplane.com>
64d983f79SMatthew Dillon  *
74d983f79SMatthew Dillon  * Redistribution and use in source and binary forms, with or without
84d983f79SMatthew Dillon  * modification, are permitted provided that the following conditions
94d983f79SMatthew Dillon  * are met:
104d983f79SMatthew Dillon  *
114d983f79SMatthew Dillon  * 1. Redistributions of source code must retain the above copyright
124d983f79SMatthew Dillon  *    notice, this list of conditions and the following disclaimer.
134d983f79SMatthew Dillon  * 2. Redistributions in binary form must reproduce the above copyright
144d983f79SMatthew Dillon  *    notice, this list of conditions and the following disclaimer in
154d983f79SMatthew Dillon  *    the documentation and/or other materials provided with the
164d983f79SMatthew Dillon  *    distribution.
174d983f79SMatthew Dillon  * 3. Neither the name of The DragonFly Project nor the names of its
184d983f79SMatthew Dillon  *    contributors may be used to endorse or promote products derived
194d983f79SMatthew Dillon  *    from this software without specific, prior written permission.
204d983f79SMatthew Dillon  *
214d983f79SMatthew Dillon  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
224d983f79SMatthew Dillon  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
234d983f79SMatthew Dillon  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
244d983f79SMatthew Dillon  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
254d983f79SMatthew Dillon  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
264d983f79SMatthew Dillon  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
274d983f79SMatthew Dillon  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
284d983f79SMatthew Dillon  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
294d983f79SMatthew Dillon  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
304d983f79SMatthew Dillon  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
314d983f79SMatthew Dillon  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
324d983f79SMatthew Dillon  * SUCH DAMAGE.
334d983f79SMatthew Dillon  */
344d983f79SMatthew Dillon 
354d983f79SMatthew Dillon #include <sys/types.h>
364d983f79SMatthew Dillon #include <sys/sysctl.h>
374d983f79SMatthew Dillon 
384d983f79SMatthew Dillon #include <ctype.h>
394d983f79SMatthew Dillon #include <devinfo.h>
404d983f79SMatthew Dillon #include <err.h>
414d983f79SMatthew Dillon #include <fcntl.h>
424d983f79SMatthew Dillon #include <kvm.h>
434d983f79SMatthew Dillon #include <limits.h>
444d983f79SMatthew Dillon #include <nlist.h>
454d983f79SMatthew Dillon #include <stdint.h>
464d983f79SMatthew Dillon #include <stdio.h>
474d983f79SMatthew Dillon #include <stdlib.h>
484d983f79SMatthew Dillon #include <string.h>
494d983f79SMatthew Dillon #include <unistd.h>
504d983f79SMatthew Dillon #include <evtr.h>
514d983f79SMatthew Dillon #include <stdarg.h>
524d983f79SMatthew Dillon #include "symbols.h"
534d983f79SMatthew Dillon 
544d983f79SMatthew Dillon struct symdata {
55*91dc43ddSMatthew Dillon 	RB_ENTRY(symdata) node;
564d983f79SMatthew Dillon 	const char *symname;
57*91dc43ddSMatthew Dillon 	char *symaddr_beg;
58*91dc43ddSMatthew Dillon 	char *symaddr_end;
594d983f79SMatthew Dillon 	char symtype;
604d983f79SMatthew Dillon };
614d983f79SMatthew Dillon 
62*91dc43ddSMatthew Dillon static int symdata_cmp(struct symdata *s1, struct symdata *s2);
63*91dc43ddSMatthew Dillon 
64*91dc43ddSMatthew Dillon RB_HEAD(symdata_rbtree, symdata);
65*91dc43ddSMatthew Dillon RB_PROTOTYPE3(symdata_rbtree, symdata, node, symdata_cmp, char *);
66*91dc43ddSMatthew Dillon RB_GENERATE3(symdata_rbtree, symdata, node, symdata_cmp, char *,
67*91dc43ddSMatthew Dillon 		symaddr_beg, symaddr_end);
68*91dc43ddSMatthew Dillon 
69*91dc43ddSMatthew Dillon static struct symdata_rbtree symroot = RB_INITIALIZER(symroot);
70e32d3244SMatthew Dillon static char *symbegin = (void *)(intptr_t)0;
71e32d3244SMatthew Dillon static char *symend = (void *)(intptr_t)-1;
724d983f79SMatthew Dillon 
73*91dc43ddSMatthew Dillon 
744d983f79SMatthew Dillon void
read_symbols(const char * file)754d983f79SMatthew Dillon read_symbols(const char *file)
764d983f79SMatthew Dillon {
774d983f79SMatthew Dillon 	char buf[256];
784d983f79SMatthew Dillon 	char cmd[256];
794d983f79SMatthew Dillon 	size_t buflen = sizeof(buf);
804d983f79SMatthew Dillon 	FILE *fp;
81*91dc43ddSMatthew Dillon 	struct symdata *lsym;
824d983f79SMatthew Dillon 	struct symdata *sym;
834d983f79SMatthew Dillon 	char *s1;
844d983f79SMatthew Dillon 	char *s2;
854d983f79SMatthew Dillon 	char *s3;
864d983f79SMatthew Dillon 
87*91dc43ddSMatthew Dillon 	RB_INIT(&symroot);
884d983f79SMatthew Dillon 
894d983f79SMatthew Dillon 	if (file == NULL) {
904d983f79SMatthew Dillon 		if (sysctlbyname("kern.bootfile", buf, &buflen, NULL, 0) < 0)
914d983f79SMatthew Dillon 			file = "/boot/kernel";
924d983f79SMatthew Dillon 		else
934d983f79SMatthew Dillon 			file = buf;
944d983f79SMatthew Dillon 	}
954d983f79SMatthew Dillon 	snprintf(cmd, sizeof(cmd), "nm -n %s", file);
964d983f79SMatthew Dillon 	if ((fp = popen(cmd, "r")) != NULL) {
97*91dc43ddSMatthew Dillon 		lsym = NULL;
984d983f79SMatthew Dillon 		while (fgets(buf, sizeof(buf), fp) != NULL) {
994d983f79SMatthew Dillon 		    s1 = strtok(buf, " \t\n");
1004d983f79SMatthew Dillon 		    s2 = strtok(NULL, " \t\n");
1014d983f79SMatthew Dillon 		    s3 = strtok(NULL, " \t\n");
1024d983f79SMatthew Dillon 		    if (s1 && s2 && s3) {
1034d983f79SMatthew Dillon 			sym = malloc(sizeof(struct symdata));
104*91dc43ddSMatthew Dillon 			sym->symaddr_beg = (char *)strtoul(s1, NULL, 16);
105*91dc43ddSMatthew Dillon 			sym->symaddr_end = sym->symaddr_beg;
106*91dc43ddSMatthew Dillon 			if (lsym)
107*91dc43ddSMatthew Dillon 				lsym->symaddr_end = sym->symaddr_beg - 1;
1084d983f79SMatthew Dillon 			sym->symtype = s2[0];
1094d983f79SMatthew Dillon 			sym->symname = strdup(s3);
1104d983f79SMatthew Dillon 			if (strcmp(s3, "kernbase") == 0)
111*91dc43ddSMatthew Dillon 				symbegin = sym->symaddr_beg;
1124d983f79SMatthew Dillon 			if (strcmp(s3, "end") == 0)
113*91dc43ddSMatthew Dillon 				symend = sym->symaddr_beg;
114*91dc43ddSMatthew Dillon 			RB_INSERT(symdata_rbtree, &symroot, sym);
115*91dc43ddSMatthew Dillon 			lsym = sym;
1164d983f79SMatthew Dillon 		    }
1174d983f79SMatthew Dillon 		}
1184d983f79SMatthew Dillon 		pclose(fp);
1194d983f79SMatthew Dillon 	}
1204d983f79SMatthew Dillon }
1214d983f79SMatthew Dillon 
1224d983f79SMatthew Dillon const char *
address_to_symbol(void * kptr,struct save_ctx * ctx)1234d983f79SMatthew Dillon address_to_symbol(void *kptr, struct save_ctx *ctx)
1244d983f79SMatthew Dillon {
125*91dc43ddSMatthew Dillon 	static struct symdata *sym;
1264d983f79SMatthew Dillon 	char *buf = ctx->save_buf;
1274d983f79SMatthew Dillon 	int size = sizeof(ctx->save_buf);
1284d983f79SMatthew Dillon 
129*91dc43ddSMatthew Dillon 	sym = RB_RLOOKUP(symdata_rbtree, &symroot, (char *)kptr);
130*91dc43ddSMatthew Dillon 	if (sym) {
131*91dc43ddSMatthew Dillon 		snprintf(buf, size, "%s+%d", sym->symname,
132*91dc43ddSMatthew Dillon 			(int)((char *)kptr - sym->symaddr_beg));
133*91dc43ddSMatthew Dillon 	} else {
1344d983f79SMatthew Dillon 		snprintf(buf, size, "%p", kptr);
135*91dc43ddSMatthew Dillon 	}
1364d983f79SMatthew Dillon 	return(buf);
1374d983f79SMatthew Dillon }
138*91dc43ddSMatthew Dillon 
139*91dc43ddSMatthew Dillon static int
symdata_cmp(struct symdata * s1,struct symdata * s2)140*91dc43ddSMatthew Dillon symdata_cmp(struct symdata *s1, struct symdata *s2)
141*91dc43ddSMatthew Dillon {
142*91dc43ddSMatthew Dillon 	if (s1->symaddr_beg < s2->symaddr_beg)
143*91dc43ddSMatthew Dillon 		return -1;
144*91dc43ddSMatthew Dillon 	if (s1->symaddr_beg > s2->symaddr_beg)
145*91dc43ddSMatthew Dillon 		return 1;
146*91dc43ddSMatthew Dillon 	return 0;
1474d983f79SMatthew Dillon }
148