4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
29 #include <sys/ksyms.h>
30 #include <sys/systm.h>
31 #include <sys/sysmacros.h>
32 #include <sys/debug.h>
33 #include <sys/cmn_err.h>
35 static const char ksyms_shstrtab
[] = "\0.symtab\0.strtab\0.shstrtab\0";
38 #define KSHDR_SYMTAB 1
39 #define KSHDR_STRTAB 2
40 #define KSHDR_SHSTRTAB 3
43 typedef struct ksyms_header
{
44 Ehdr elf_hdr
; /* Elf file header */
45 Phdr text_phdr
; /* text program header */
46 Phdr data_phdr
; /* data program header */
47 Shdr shdr
[KSHDR_NUM
]; /* section headers */
48 char shstrings
[sizeof (ksyms_shstrtab
)]; /* shstrtab strings */
53 #define KW_GLOBALS 0x4
54 #define KW_STRINGS 0x8
56 typedef struct ksyms_walkinfo
{
57 void (*kw_emit
)(const void *, void *, size_t);
62 size_t kw_size
[KW_STRINGS
+ 1];
69 ksyms_emit(ksyms_walkinfo_t
*kwp
, void *src
, size_t size
, int action
)
71 if (kwp
->kw_actions
& action
) {
72 if ((kwp
->kw_resid
-= size
) >= 0)
73 kwp
->kw_emit(src
, kwp
->kw_target
, size
);
74 kwp
->kw_totalsize
+= size
;
76 kwp
->kw_size
[action
] += size
;
81 ksyms_walk_one(void *arg
, void *base
, size_t size
)
83 ksyms_walkinfo_t
*kwp
= arg
;
85 Shdr
*strhdr
= symhdr
+ symhdr
->sh_link
;
86 size_t symsize
= symhdr
->sh_entsize
;
87 size_t nsyms
= symhdr
->sh_size
/ symsize
;
88 char *strings
= (char *)strhdr
->sh_addr
;
91 for (i
= 1; i
< nsyms
; i
++) {
92 Sym
*sym
= (Sym
*)(symhdr
->sh_addr
+ i
* symsize
);
94 char *name
= strings
+ sym
->st_name
;
95 tmp
.st_name
= kwp
->kw_size
[KW_STRINGS
];
96 tmp
.st_shndx
= SHN_ABS
;
97 ksyms_emit(kwp
, &tmp
, sizeof (Sym
),
98 ELF_ST_BIND(sym
->st_info
) == STB_LOCAL
?
99 KW_LOCALS
: KW_GLOBALS
);
100 ksyms_emit(kwp
, name
, strlen(name
) + 1, KW_STRINGS
);
105 ksyms_walk(ksyms_walkinfo_t
*kwp
, void *target
, ssize_t resid
,
106 void (*emit
)(const void *, void *, size_t), void *src
, int actions
)
110 bzero(kwp
, sizeof (ksyms_walkinfo_t
));
112 kwp
->kw_target
= target
;
113 kwp
->kw_resid
= resid
;
114 kwp
->kw_actions
= actions
;
116 ksyms_emit(kwp
, src
, sizeof (ksyms_header_t
), KW_HEADER
);
118 * The first symbol table entry is all zeroes; it's unused
119 * because index 0 marks the end of symbol hash chains.
121 bzero(&tmp
, sizeof (Sym
));
122 ksyms_emit(kwp
, &tmp
, sizeof (Sym
), KW_LOCALS
);
123 ksyms_emit(kwp
, &tmp
, 1, KW_STRINGS
);
124 vmem_walk(ksyms_arena
, VMEM_ALLOC
, ksyms_walk_one
, kwp
);
125 return (kwp
->kw_totalsize
);
129 ksyms_snapshot(void (*emit
)(const void *, void *, size_t),
130 void *buf
, size_t len
)
134 ssize_t size
= 0, bufsize
= len
;
137 rw_enter(&ksyms_lock
, RW_READER
);
140 * Compute the size of the header, locals, globals, and strings.
142 (void) ksyms_walk(&kw
, NULL
, 0, NULL
, NULL
,
143 KW_HEADER
| KW_LOCALS
| KW_GLOBALS
| KW_STRINGS
);
146 * Construct the ELF header.
148 bzero(&hdr
, sizeof (hdr
));
150 hdr
.elf_hdr
= ((struct module
*)modules
.mod_mp
)->hdr
;
151 hdr
.elf_hdr
.e_phoff
= offsetof(ksyms_header_t
, text_phdr
);
152 hdr
.elf_hdr
.e_shoff
= offsetof(ksyms_header_t
, shdr
);
153 hdr
.elf_hdr
.e_phnum
= 2;
154 hdr
.elf_hdr
.e_shnum
= KSHDR_NUM
;
155 hdr
.elf_hdr
.e_shstrndx
= KSHDR_SHSTRTAB
;
157 hdr
.text_phdr
.p_type
= PT_LOAD
;
158 hdr
.text_phdr
.p_vaddr
= (Addr
)s_text
;
159 hdr
.text_phdr
.p_memsz
= (Word
)(e_text
- s_text
);
160 hdr
.text_phdr
.p_flags
= PF_R
| PF_X
;
162 hdr
.data_phdr
.p_type
= PT_LOAD
;
163 hdr
.data_phdr
.p_vaddr
= (Addr
)s_data
;
164 hdr
.data_phdr
.p_memsz
= (Word
)(e_data
- s_data
);
165 hdr
.data_phdr
.p_flags
= PF_R
| PF_W
| PF_X
;
167 shp
= &hdr
.shdr
[KSHDR_SYMTAB
];
168 shp
->sh_name
= 1; /* ksyms_shstrtab[1] = ".symtab" */
169 shp
->sh_type
= SHT_SYMTAB
;
170 shp
->sh_offset
= kw
.kw_size
[KW_HEADER
];
171 shp
->sh_size
= kw
.kw_size
[KW_LOCALS
] + kw
.kw_size
[KW_GLOBALS
];
172 shp
->sh_link
= KSHDR_STRTAB
;
173 shp
->sh_info
= kw
.kw_size
[KW_LOCALS
] / sizeof (Sym
);
174 shp
->sh_addralign
= sizeof (Addr
);
175 shp
->sh_entsize
= sizeof (Sym
);
177 shp
= &hdr
.shdr
[KSHDR_STRTAB
];
178 shp
->sh_name
= 9; /* ksyms_shstrtab[9] = ".strtab" */
179 shp
->sh_type
= SHT_STRTAB
;
180 shp
->sh_offset
= kw
.kw_size
[KW_HEADER
] +
181 kw
.kw_size
[KW_LOCALS
] + kw
.kw_size
[KW_GLOBALS
];
182 shp
->sh_size
= kw
.kw_size
[KW_STRINGS
];
183 shp
->sh_addralign
= 1;
185 shp
= &hdr
.shdr
[KSHDR_SHSTRTAB
];
186 shp
->sh_name
= 17; /* ksyms_shstrtab[17] = ".shstrtab" */
187 shp
->sh_type
= SHT_STRTAB
;
188 shp
->sh_offset
= offsetof(ksyms_header_t
, shstrings
);
189 shp
->sh_size
= sizeof (ksyms_shstrtab
);
190 shp
->sh_addralign
= 1;
192 bcopy(ksyms_shstrtab
, hdr
.shstrings
, sizeof (ksyms_shstrtab
));
195 * Emit the symbol table.
197 size
+= ksyms_walk(&kw
, buf
, (bufsize
- size
), emit
, &hdr
,
199 size
+= ksyms_walk(&kw
, buf
, (bufsize
- size
), emit
,
201 size
+= ksyms_walk(&kw
, buf
, (bufsize
- size
), emit
,
203 size
+= ksyms_walk(&kw
, buf
, (bufsize
- size
), emit
, NULL
,
206 rw_exit(&ksyms_lock
);
208 return ((size_t)size
);