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"
35 #include <sys/types.h>
41 #include <sys/tnf_com.h>
45 #define TNFDEV "/dev/tnfmap"
51 tnf_uint32_t generation
;
52 tnf_uint16_t bytes_valid
;
55 static char *dumpfile
; /* Dump file if extracting from crashdump */
56 static char *namelist
; /* Symbol tbl. if extracting from crashdump */
57 static kvm_t
*kvm_p
; /* Handle for kvm_open, kvm_read, ... */
59 static struct nlist kvm_syms
[] = {
61 { "tnf_trace_file_size" },
65 static uintptr_t dump_bufaddr
;
66 static size_t tnf_bufsize
;
67 static char *program_name
;
70 static tnf_file_header_t
*tnf_header
;
73 * usage() - gives a description of the arguments, and exits
77 usage(char *argv
[], const char *msg
)
80 (void) fprintf(stderr
,
81 gettext("%s: %s\n"), argv
[0], msg
);
83 (void) fprintf(stderr
, gettext(
84 "usage: %s [-d <dumpfile> -n <symbolfile> ] "
85 "<output-filename>\n"), argv
[0]);
91 * Write 'size' bytes at offset 'offset' from 'addr'
92 * to the output file. Bail out unceremoniously if anything goes wrong.
95 writeout(char *addr
, int offset
, int size
)
98 if (lseek(output_fd
, offset
, SEEK_SET
) < 0) {
102 if (write(output_fd
, addr
, size
) != size
) {
113 kvm_p
= kvm_open(namelist
, dumpfile
, NULL
, O_RDONLY
, program_name
);
115 /* kvm_open prints an error message */
118 if (kvm_nlist(kvm_p
, kvm_syms
) != 0) {
119 (void) fprintf(stderr
, gettext(
120 "Symbol lookup error in %s\n"), namelist
);
123 if (kvm_read(kvm_p
, kvm_syms
[0].n_value
, (char *) &dump_bufaddr
,
124 sizeof (dump_bufaddr
)) != sizeof (dump_bufaddr
) ||
125 kvm_read(kvm_p
, kvm_syms
[1].n_value
, (char *) &tnf_bufsize
,
126 sizeof (tnf_bufsize
)) != sizeof (tnf_bufsize
)) {
127 (void) fprintf(stderr
, gettext(
128 "kvm_read error in %s\n"), dumpfile
);
131 if (dump_bufaddr
== NULL
|| tnf_bufsize
== 0) {
132 (void) fprintf(stderr
, gettext(
133 "No trace data available in the kernel.\n"));
142 tifiocstate_t tstate
;
144 if ((input_fd
= open(TNFDEV
, O_RDWR
)) < 0) {
148 if (ioctl(input_fd
, TIFIOCGSTATE
, &tstate
) < 0) {
149 perror(gettext("Error getting trace system state"));
152 if (tstate
.buffer_state
!= TIFIOCBUF_OK
) {
153 (void) fprintf(stderr
, gettext(
154 "No trace data available in the kernel.\n"));
157 tnf_bufsize
= tstate
.buffer_size
;
161 read_tnf_header(char *addr
)
164 if (dumpfile
!= NULL
) {
165 if (kvm_read(kvm_p
, dump_bufaddr
, addr
, 512) != 512) {
166 (void) fprintf(stderr
, gettext(
167 "Error reading tnf header from dump file.\n"));
171 if (ioctl(input_fd
, TIFIOCGHEADER
, addr
) != 0) {
172 perror(gettext("Error reading tnf header from kernel"));
179 read_tnf_block(tnf_block_header_t
*addr
, int block_num
)
183 tifiocgblock_t ioctl_arg
;
185 if (dumpfile
!= NULL
) {
186 offset
= tnf_header
->directory_size
+
187 block_num
* tnf_header
->block_size
;
188 if (kvm_read(kvm_p
, dump_bufaddr
+ offset
, (char *) addr
,
189 tnf_header
->block_size
) != tnf_header
->block_size
) {
190 (void) fprintf(stderr
, gettext(
191 "Error reading tnf block.\n"));
195 ioctl_arg
.dst_addr
= (char *) addr
;
196 ioctl_arg
.block_num
= block_num
;
197 if (ioctl(input_fd
, TIFIOCGBLOCK
, &ioctl_arg
) < 0) {
200 perror(gettext("Error reading tnf block"));
208 read_tnf_fwzone(tnf_ref32_t
*dest
, int start
, int slots
)
213 tifiocgfw_t ioctl_arg
;
215 if (dumpfile
!= NULL
) {
216 /* LINTED assignment of 64-bit integer to 32-bit integer */
217 offset
= tnf_header
->block_size
+ start
* sizeof (tnf_ref32_t
);
218 /* LINTED assignment of 64-bit integer to 32-bit integer */
219 len
= slots
* sizeof (tnf_ref32_t
);
220 if (kvm_read(kvm_p
, dump_bufaddr
+ offset
, (char *) dest
,
222 (void) fprintf(stderr
, gettext(
223 "Error reading tnf forwarding zone.\n"));
227 /* LINTED pointer cast may result in improper alignment */
228 ioctl_arg
.dst_addr
= (long *) dest
;
229 ioctl_arg
.start
= start
;
230 ioctl_arg
.slots
= slots
;
231 if (ioctl(input_fd
, TIFIOCGFWZONE
, &ioctl_arg
) < 0) {
232 perror(gettext("Error reading tnf block"));
239 main(int argc
, char *argv
[])
241 const char *optstr
= "d:n:";
245 tnf_uint32_t
*magicp
;
246 tnf_block_header_t
*block_base
, *blockp
;
247 BLOCK_STATUS
*block_stat
, *bsp
;
249 boolean_t any_unread
, any_different
, retry
;
256 program_name
= argv
[0];
257 while ((c
= getopt(argc
, argv
, optstr
)) != EOF
) {
266 usage(argv
, gettext("unrecognized argument"));
269 if (optind
!= argc
- 1) {
270 usage(argv
, gettext("too many or too few arguments"));
272 outfile
= argv
[optind
];
274 if ((dumpfile
!= NULL
) ^ (namelist
!= NULL
)) {
275 usage(argv
, gettext("must specify both or neither of the "
276 "-d and -n options"));
279 output_fd
= open(outfile
, O_WRONLY
| O_CREAT
| O_TRUNC
, 0600);
284 if (dumpfile
!= NULL
)
289 if ((local_buf
= malloc(tnf_bufsize
)) == NULL
) {
290 (void) fprintf(stderr
,
291 gettext("tnfxtract memory allocation failure\n"));
295 /* Read header, get block size, check for version mismatch */
296 read_tnf_header(local_buf
);
297 /*LINTED pointer cast may result in improper alignment*/
298 magicp
= (tnf_uint32_t
*) local_buf
;
299 /*LINTED pointer cast may result in improper alignment*/
300 tnf_header
= (tnf_file_header_t
*)(local_buf
+ sizeof (*magicp
));
301 if (*magicp
!= TNF_MAGIC
) {
302 (void) fprintf(stderr
, gettext(
303 "Buffer is not in TNF format.\n"));
306 if (tnf_header
->file_version
!= TNF_FILE_VERSION
) {
307 (void) fprintf(stderr
,
308 gettext("Version mismatch (tnfxtract: %d; buffer: %d)\n"),
309 TNF_FILE_VERSION
, tnf_header
->file_version
);
312 writeout(local_buf
, 0, tnf_header
->block_size
);
313 /* LINTED pointer cast may result in improper alignment */
314 block_base
= (tnf_block_header_t
*)
315 (local_buf
+ tnf_header
->directory_size
);
316 block_count
= tnf_header
->block_count
-
317 tnf_header
->directory_size
/ tnf_header
->block_size
;
318 fwzonesize
= tnf_header
->directory_size
- tnf_header
->block_size
;
320 block_stat
= (BLOCK_STATUS
*)
321 calloc(block_count
, sizeof (BLOCK_STATUS
));
322 if (block_stat
== NULL
) {
323 (void) fprintf(stderr
,
324 gettext("tnfxtract memory allocation failure\n"));
328 for (bsp
= block_stat
; bsp
!= block_stat
+ block_count
; ++bsp
)
329 bsp
->ever_read
= B_FALSE
;
331 * Make repeated passes until we've read every non-tag block.
334 any_unread
= B_FALSE
;
338 while (block_num
!= block_count
) {
339 if (!bsp
->ever_read
) {
340 if (read_tnf_block(blockp
, block_num
) != 0)
343 bsp
->ever_read
= B_TRUE
;
344 bsp
->generation
= blockp
->generation
;
345 bsp
->bytes_valid
= blockp
->bytes_valid
;
346 writeout((char *) blockp
,
347 /* LINTED cast 64 to 32 bit */
348 (int)((char *) blockp
- local_buf
),
349 tnf_header
->block_size
);
354 /* LINTED pointer cast may result in improper alignment */
355 blockp
= (tnf_block_header_t
*)
356 ((char *) blockp
+ tnf_header
->block_size
);
358 } while (any_unread
);
361 * Then read tag blocks only, until we have two consecutive,
365 any_different
= B_FALSE
;
369 while (block_num
!= block_count
) {
370 if (read_tnf_block(blockp
, block_num
) == 0 &&
371 blockp
->generation
== TNF_TAG_GENERATION_NUM
&&
372 (bsp
->generation
!= TNF_TAG_GENERATION_NUM
||
373 bsp
->bytes_valid
!= blockp
->bytes_valid
)) {
374 bsp
->generation
= TNF_TAG_GENERATION_NUM
;
375 bsp
->bytes_valid
= blockp
->bytes_valid
;
376 writeout((char *) blockp
,
377 /* LINTED cast 64bit to 32 bit */
378 (int)((char *) blockp
- local_buf
),
379 tnf_header
->block_size
);
380 any_different
= B_TRUE
;
384 /* LINTED pointer cast may result in improper alignment */
385 blockp
= (tnf_block_header_t
*)
386 ((char *) blockp
+ tnf_header
->block_size
);
388 } while (any_different
);
391 * Then read the forwarding pointers. If any are -1:
392 * sleep briefly, then make another pass.
394 /*LINTED pointer cast may result in improper alignment*/
395 fwzone
= (tnf_ref32_t
*)(local_buf
+ tnf_header
->block_size
);
397 read_tnf_fwzone(fwzone
, 0,
398 /* LINTED cast from 64-bit integer to 32-bit integer */
399 (int)(fwzonesize
/ sizeof (fwzone
[0])));
401 while (fwtries
!= MAXFWTRY
) {
403 for (i
= 0; i
!= fwzonesize
/ sizeof (fwzone
[0]); ++i
) {
404 if (fwzone
[i
] == -1) {
405 read_tnf_fwzone(&fwzone
[i
], i
, 1);
416 if (fwtries
== MAXFWTRY
) {
417 (void) fprintf(stderr
, gettext(
418 "Warning: forwarding pointers may "
421 writeout((char *) fwzone
, tnf_header
->block_size
, fwzonesize
);