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 #include <sys/ksyms.h>
30*0Sstevel@tonic-gate #include <sys/systm.h>
31*0Sstevel@tonic-gate #include <sys/sysmacros.h>
32*0Sstevel@tonic-gate #include <sys/debug.h>
33*0Sstevel@tonic-gate #include <sys/cmn_err.h>
34*0Sstevel@tonic-gate
35*0Sstevel@tonic-gate static const char ksyms_shstrtab[] = "\0.symtab\0.strtab\0.shstrtab\0";
36*0Sstevel@tonic-gate
37*0Sstevel@tonic-gate #define KSHDR_NULL 0
38*0Sstevel@tonic-gate #define KSHDR_SYMTAB 1
39*0Sstevel@tonic-gate #define KSHDR_STRTAB 2
40*0Sstevel@tonic-gate #define KSHDR_SHSTRTAB 3
41*0Sstevel@tonic-gate #define KSHDR_NUM 4
42*0Sstevel@tonic-gate
43*0Sstevel@tonic-gate typedef struct ksyms_header {
44*0Sstevel@tonic-gate Ehdr elf_hdr; /* Elf file header */
45*0Sstevel@tonic-gate Phdr text_phdr; /* text program header */
46*0Sstevel@tonic-gate Phdr data_phdr; /* data program header */
47*0Sstevel@tonic-gate Shdr shdr[KSHDR_NUM]; /* section headers */
48*0Sstevel@tonic-gate char shstrings[sizeof (ksyms_shstrtab)]; /* shstrtab strings */
49*0Sstevel@tonic-gate } ksyms_header_t;
50*0Sstevel@tonic-gate
51*0Sstevel@tonic-gate #define KW_HEADER 0x1
52*0Sstevel@tonic-gate #define KW_LOCALS 0x2
53*0Sstevel@tonic-gate #define KW_GLOBALS 0x4
54*0Sstevel@tonic-gate #define KW_STRINGS 0x8
55*0Sstevel@tonic-gate
56*0Sstevel@tonic-gate typedef struct ksyms_walkinfo {
57*0Sstevel@tonic-gate void (*kw_emit)(const void *, void *, size_t);
58*0Sstevel@tonic-gate char *kw_target;
59*0Sstevel@tonic-gate ssize_t kw_resid;
60*0Sstevel@tonic-gate ssize_t kw_totalsize;
61*0Sstevel@tonic-gate int kw_actions;
62*0Sstevel@tonic-gate size_t kw_size[KW_STRINGS + 1];
63*0Sstevel@tonic-gate } ksyms_walkinfo_t;
64*0Sstevel@tonic-gate
65*0Sstevel@tonic-gate krwlock_t ksyms_lock;
66*0Sstevel@tonic-gate vmem_t *ksyms_arena;
67*0Sstevel@tonic-gate
68*0Sstevel@tonic-gate static void
ksyms_emit(ksyms_walkinfo_t * kwp,void * src,size_t size,int action)69*0Sstevel@tonic-gate ksyms_emit(ksyms_walkinfo_t *kwp, void *src, size_t size, int action)
70*0Sstevel@tonic-gate {
71*0Sstevel@tonic-gate if (kwp->kw_actions & action) {
72*0Sstevel@tonic-gate if ((kwp->kw_resid -= size) >= 0)
73*0Sstevel@tonic-gate kwp->kw_emit(src, kwp->kw_target, size);
74*0Sstevel@tonic-gate kwp->kw_totalsize += size;
75*0Sstevel@tonic-gate }
76*0Sstevel@tonic-gate kwp->kw_size[action] += size;
77*0Sstevel@tonic-gate }
78*0Sstevel@tonic-gate
79*0Sstevel@tonic-gate /*ARGSUSED*/
80*0Sstevel@tonic-gate static void
ksyms_walk_one(void * arg,void * base,size_t size)81*0Sstevel@tonic-gate ksyms_walk_one(void *arg, void *base, size_t size)
82*0Sstevel@tonic-gate {
83*0Sstevel@tonic-gate ksyms_walkinfo_t *kwp = arg;
84*0Sstevel@tonic-gate Shdr *symhdr = base;
85*0Sstevel@tonic-gate Shdr *strhdr = symhdr + symhdr->sh_link;
86*0Sstevel@tonic-gate size_t symsize = symhdr->sh_entsize;
87*0Sstevel@tonic-gate size_t nsyms = symhdr->sh_size / symsize;
88*0Sstevel@tonic-gate char *strings = (char *)strhdr->sh_addr;
89*0Sstevel@tonic-gate int i;
90*0Sstevel@tonic-gate
91*0Sstevel@tonic-gate for (i = 1; i < nsyms; i++) {
92*0Sstevel@tonic-gate Sym *sym = (Sym *)(symhdr->sh_addr + i * symsize);
93*0Sstevel@tonic-gate Sym tmp = *sym;
94*0Sstevel@tonic-gate char *name = strings + sym->st_name;
95*0Sstevel@tonic-gate tmp.st_name = kwp->kw_size[KW_STRINGS];
96*0Sstevel@tonic-gate tmp.st_shndx = SHN_ABS;
97*0Sstevel@tonic-gate ksyms_emit(kwp, &tmp, sizeof (Sym),
98*0Sstevel@tonic-gate ELF_ST_BIND(sym->st_info) == STB_LOCAL ?
99*0Sstevel@tonic-gate KW_LOCALS : KW_GLOBALS);
100*0Sstevel@tonic-gate ksyms_emit(kwp, name, strlen(name) + 1, KW_STRINGS);
101*0Sstevel@tonic-gate }
102*0Sstevel@tonic-gate }
103*0Sstevel@tonic-gate
104*0Sstevel@tonic-gate static ssize_t
ksyms_walk(ksyms_walkinfo_t * kwp,void * target,ssize_t resid,void (* emit)(const void *,void *,size_t),void * src,int actions)105*0Sstevel@tonic-gate ksyms_walk(ksyms_walkinfo_t *kwp, void *target, ssize_t resid,
106*0Sstevel@tonic-gate void (*emit)(const void *, void *, size_t), void *src, int actions)
107*0Sstevel@tonic-gate {
108*0Sstevel@tonic-gate Sym tmp;
109*0Sstevel@tonic-gate
110*0Sstevel@tonic-gate bzero(kwp, sizeof (ksyms_walkinfo_t));
111*0Sstevel@tonic-gate kwp->kw_emit = emit;
112*0Sstevel@tonic-gate kwp->kw_target = target;
113*0Sstevel@tonic-gate kwp->kw_resid = resid;
114*0Sstevel@tonic-gate kwp->kw_actions = actions;
115*0Sstevel@tonic-gate
116*0Sstevel@tonic-gate ksyms_emit(kwp, src, sizeof (ksyms_header_t), KW_HEADER);
117*0Sstevel@tonic-gate /*
118*0Sstevel@tonic-gate * The first symbol table entry is all zeroes; it's unused
119*0Sstevel@tonic-gate * because index 0 marks the end of symbol hash chains.
120*0Sstevel@tonic-gate */
121*0Sstevel@tonic-gate bzero(&tmp, sizeof (Sym));
122*0Sstevel@tonic-gate ksyms_emit(kwp, &tmp, sizeof (Sym), KW_LOCALS);
123*0Sstevel@tonic-gate ksyms_emit(kwp, &tmp, 1, KW_STRINGS);
124*0Sstevel@tonic-gate vmem_walk(ksyms_arena, VMEM_ALLOC, ksyms_walk_one, kwp);
125*0Sstevel@tonic-gate return (kwp->kw_totalsize);
126*0Sstevel@tonic-gate }
127*0Sstevel@tonic-gate
128*0Sstevel@tonic-gate size_t
ksyms_snapshot(void (* emit)(const void *,void *,size_t),void * buf,size_t len)129*0Sstevel@tonic-gate ksyms_snapshot(void (*emit)(const void *, void *, size_t),
130*0Sstevel@tonic-gate void *buf, size_t len)
131*0Sstevel@tonic-gate {
132*0Sstevel@tonic-gate ksyms_walkinfo_t kw;
133*0Sstevel@tonic-gate ksyms_header_t hdr;
134*0Sstevel@tonic-gate ssize_t size = 0, bufsize = len;
135*0Sstevel@tonic-gate Shdr *shp;
136*0Sstevel@tonic-gate
137*0Sstevel@tonic-gate rw_enter(&ksyms_lock, RW_READER);
138*0Sstevel@tonic-gate
139*0Sstevel@tonic-gate /*
140*0Sstevel@tonic-gate * Compute the size of the header, locals, globals, and strings.
141*0Sstevel@tonic-gate */
142*0Sstevel@tonic-gate (void) ksyms_walk(&kw, NULL, 0, NULL, NULL,
143*0Sstevel@tonic-gate KW_HEADER | KW_LOCALS | KW_GLOBALS | KW_STRINGS);
144*0Sstevel@tonic-gate
145*0Sstevel@tonic-gate /*
146*0Sstevel@tonic-gate * Construct the ELF header.
147*0Sstevel@tonic-gate */
148*0Sstevel@tonic-gate bzero(&hdr, sizeof (hdr));
149*0Sstevel@tonic-gate
150*0Sstevel@tonic-gate hdr.elf_hdr = ((struct module *)modules.mod_mp)->hdr;
151*0Sstevel@tonic-gate hdr.elf_hdr.e_phoff = offsetof(ksyms_header_t, text_phdr);
152*0Sstevel@tonic-gate hdr.elf_hdr.e_shoff = offsetof(ksyms_header_t, shdr);
153*0Sstevel@tonic-gate hdr.elf_hdr.e_phnum = 2;
154*0Sstevel@tonic-gate hdr.elf_hdr.e_shnum = KSHDR_NUM;
155*0Sstevel@tonic-gate hdr.elf_hdr.e_shstrndx = KSHDR_SHSTRTAB;
156*0Sstevel@tonic-gate
157*0Sstevel@tonic-gate hdr.text_phdr.p_type = PT_LOAD;
158*0Sstevel@tonic-gate hdr.text_phdr.p_vaddr = (Addr)s_text;
159*0Sstevel@tonic-gate hdr.text_phdr.p_memsz = (Word)(e_text - s_text);
160*0Sstevel@tonic-gate hdr.text_phdr.p_flags = PF_R | PF_X;
161*0Sstevel@tonic-gate
162*0Sstevel@tonic-gate hdr.data_phdr.p_type = PT_LOAD;
163*0Sstevel@tonic-gate hdr.data_phdr.p_vaddr = (Addr)s_data;
164*0Sstevel@tonic-gate hdr.data_phdr.p_memsz = (Word)(e_data - s_data);
165*0Sstevel@tonic-gate hdr.data_phdr.p_flags = PF_R | PF_W | PF_X;
166*0Sstevel@tonic-gate
167*0Sstevel@tonic-gate shp = &hdr.shdr[KSHDR_SYMTAB];
168*0Sstevel@tonic-gate shp->sh_name = 1; /* ksyms_shstrtab[1] = ".symtab" */
169*0Sstevel@tonic-gate shp->sh_type = SHT_SYMTAB;
170*0Sstevel@tonic-gate shp->sh_offset = kw.kw_size[KW_HEADER];
171*0Sstevel@tonic-gate shp->sh_size = kw.kw_size[KW_LOCALS] + kw.kw_size[KW_GLOBALS];
172*0Sstevel@tonic-gate shp->sh_link = KSHDR_STRTAB;
173*0Sstevel@tonic-gate shp->sh_info = kw.kw_size[KW_LOCALS] / sizeof (Sym);
174*0Sstevel@tonic-gate shp->sh_addralign = sizeof (Addr);
175*0Sstevel@tonic-gate shp->sh_entsize = sizeof (Sym);
176*0Sstevel@tonic-gate
177*0Sstevel@tonic-gate shp = &hdr.shdr[KSHDR_STRTAB];
178*0Sstevel@tonic-gate shp->sh_name = 9; /* ksyms_shstrtab[9] = ".strtab" */
179*0Sstevel@tonic-gate shp->sh_type = SHT_STRTAB;
180*0Sstevel@tonic-gate shp->sh_offset = kw.kw_size[KW_HEADER] +
181*0Sstevel@tonic-gate kw.kw_size[KW_LOCALS] + kw.kw_size[KW_GLOBALS];
182*0Sstevel@tonic-gate shp->sh_size = kw.kw_size[KW_STRINGS];
183*0Sstevel@tonic-gate shp->sh_addralign = 1;
184*0Sstevel@tonic-gate
185*0Sstevel@tonic-gate shp = &hdr.shdr[KSHDR_SHSTRTAB];
186*0Sstevel@tonic-gate shp->sh_name = 17; /* ksyms_shstrtab[17] = ".shstrtab" */
187*0Sstevel@tonic-gate shp->sh_type = SHT_STRTAB;
188*0Sstevel@tonic-gate shp->sh_offset = offsetof(ksyms_header_t, shstrings);
189*0Sstevel@tonic-gate shp->sh_size = sizeof (ksyms_shstrtab);
190*0Sstevel@tonic-gate shp->sh_addralign = 1;
191*0Sstevel@tonic-gate
192*0Sstevel@tonic-gate bcopy(ksyms_shstrtab, hdr.shstrings, sizeof (ksyms_shstrtab));
193*0Sstevel@tonic-gate
194*0Sstevel@tonic-gate /*
195*0Sstevel@tonic-gate * Emit the symbol table.
196*0Sstevel@tonic-gate */
197*0Sstevel@tonic-gate size += ksyms_walk(&kw, buf, (bufsize - size), emit, &hdr,
198*0Sstevel@tonic-gate KW_HEADER);
199*0Sstevel@tonic-gate size += ksyms_walk(&kw, buf, (bufsize - size), emit,
200*0Sstevel@tonic-gate NULL, KW_LOCALS);
201*0Sstevel@tonic-gate size += ksyms_walk(&kw, buf, (bufsize - size), emit,
202*0Sstevel@tonic-gate NULL, KW_GLOBALS);
203*0Sstevel@tonic-gate size += ksyms_walk(&kw, buf, (bufsize - size), emit, NULL,
204*0Sstevel@tonic-gate KW_STRINGS);
205*0Sstevel@tonic-gate
206*0Sstevel@tonic-gate rw_exit(&ksyms_lock);
207*0Sstevel@tonic-gate
208*0Sstevel@tonic-gate return ((size_t)size);
209*0Sstevel@tonic-gate }
210