Commit | Line | Data |
---|---|---|
920dae64 AT |
1 | /* |
2 | * ========== Copyright Header Begin ========================================== | |
3 | * | |
4 | * OpenSPARC T2 Processor File: coverage.c | |
5 | * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved. | |
6 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES. | |
7 | * | |
8 | * The above named program is free software; you can redistribute it and/or | |
9 | * modify it under the terms of the GNU General Public | |
10 | * License version 2 as published by the Free Software Foundation. | |
11 | * | |
12 | * The above named program is distributed in the hope that it will be | |
13 | * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | * General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU General Public | |
18 | * License along with this work; if not, write to the Free Software | |
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. | |
20 | * | |
21 | * ========== Copyright Header End ============================================ | |
22 | */ | |
23 | /* | |
24 | * Copyright 2006 Sun Microsystems, Inc. All rights reserved. | |
25 | * Use is subject to license terms. | |
26 | */ | |
27 | #pragma ident "@(#)coverage.c 1.5 06/10/25 SMI" | |
28 | ||
29 | #include <stdio.h> | |
30 | #include <stdlib.h> | |
31 | #include <unistd.h> | |
32 | #include <sys/types.h> | |
33 | #include <sys/mman.h> | |
34 | #include <assert.h> | |
35 | #include <string.h> | |
36 | #include <strings.h> | |
37 | #include <fcntl.h> | |
38 | #include <sys/stat.h> | |
39 | #include <thread.h> | |
40 | #include <synch.h> | |
41 | ||
42 | #include "ss_common.h" | |
43 | #include "niagara.h" | |
44 | #include "coverage.h" | |
45 | ||
46 | #if 1 | |
47 | #define DBGP(s) do { s; } while (0) | |
48 | #endif | |
49 | ||
50 | void dbg_coverage(simcpu_t *sp, uint32_t rawi); | |
51 | void dbg_coverage_parse(void); | |
52 | void dbg_coverage_dump(void); | |
53 | ||
54 | /* start/end for pc,instn coverage analysis */ | |
55 | uint32_t coverage_mode; | |
56 | uint64_t start_pc = 0x0; | |
57 | uint64_t end_pc = 0x0; | |
58 | bool_t decode_instn = false; | |
59 | void *coverage_data_filep; | |
60 | ||
61 | coverage_info_t *coverage_bufp; | |
62 | ||
63 | /* | |
64 | * This will be called while parsing the conf file | |
65 | * to allow this hook to parse specific options from | |
66 | * the conf file. | |
67 | * | |
68 | * Format of coverage directive is: | |
69 | * debug_hook [coverage] [start] [end]; | |
70 | * | |
71 | * [coverage] - we've already parsed this. That's how we got here. | |
72 | * [data_file] - name of the file to mmap (will contain coverage data) | |
73 | * [start] | |
74 | * [end] - only trace when %pc is within [start]-[end] range | |
75 | * | |
76 | * All samples for %pc within the range supplied will be stored | |
77 | * in a data file (using the name provided in the directive). The | |
78 | * results of the coverage run can be viewed by running the | |
79 | * coverage_dump tool (in the build directory) at any time during | |
80 | * or after the run. | |
81 | * NOTE: this feature will not overwrite the data_file | |
82 | */ | |
83 | void | |
84 | dbg_coverage_parse(void) | |
85 | { | |
86 | lexer_tok_t tok; | |
87 | uint64_t num_of_pcs; | |
88 | int shmflg; | |
89 | uint64_t buf_size; | |
90 | char data_file[256]; | |
91 | struct stat sb; | |
92 | mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO; | |
93 | int fd; | |
94 | ||
95 | ||
96 | DBGP(printf("\nInside dbg_coverage_parse()")); | |
97 | ||
98 | /* Parse data_file to mmap in */ | |
99 | tok = lex_get_token(); | |
100 | strcpy(data_file, lex.strp); | |
101 | ||
102 | ||
103 | lex_get(T_Number); /* start pc */ | |
104 | start_pc = lex.val; | |
105 | lex_get(T_Number); /* end pc */ | |
106 | end_pc = lex.val; | |
107 | ||
108 | if (end_pc < start_pc) | |
109 | lex_fatal("end_pc needs to be larger than start_pc in conf file"); | |
110 | ||
111 | num_of_pcs = ((end_pc - start_pc) / 4) + 1; | |
112 | buf_size = ((sizeof (coverage_info_t)) * num_of_pcs); | |
113 | ||
114 | DBGP(printf("\ncoverage: start_pc=0x%llx, end_pc=0x%llx "\ | |
115 | "num_of_pcs=0x%llx, buf_size=0x%llx", | |
116 | start_pc, end_pc, num_of_pcs, buf_size)); | |
117 | ||
118 | /* | |
119 | * Setup mmap file. | |
120 | * | |
121 | * Create the empty data_file of size buf_size | |
122 | * Then mmap it into memory. | |
123 | */ | |
124 | ||
125 | /* Make sure file does not exist */ | |
126 | if (stat(data_file, &sb) == 0) | |
127 | lex_fatal("coverage: file %s already exists. Check conf file ", | |
128 | data_file); | |
129 | ||
130 | /* Create a new file */ | |
131 | if ((fd = open(data_file, O_RDWR | O_CREAT | O_TRUNC, mode)) == -1) | |
132 | fatal("Could not create data_file %s\n", data_file); | |
133 | ||
134 | /* Set the size of the file by seeking to the end and write NULL */ | |
135 | if (lseek(fd, (off_t)buf_size-1, SEEK_SET) < 0) | |
136 | fatal("Could not create data_file of size [0x%llx]", buf_size); | |
137 | ||
138 | if (write(fd, "", 1) != 1) | |
139 | fatal("Could not write to data_file of size [0x%llx]", buf_size); | |
140 | ||
141 | /* mmap file file */ | |
142 | coverage_data_filep = mmap(NULL, buf_size, PROT_READ | PROT_WRITE, | |
143 | MAP_SHARED, fd, 0); | |
144 | if (coverage_data_filep == MAP_FAILED) | |
145 | fatal("Failed to mmap %s\n", data_file); | |
146 | ||
147 | coverage_bufp = coverage_data_filep; | |
148 | ||
149 | /* | |
150 | * return to parse_debug_hook() which will take care of | |
151 | * parsing the last semi colon. | |
152 | */ | |
153 | } | |
154 | ||
155 | ||
156 | /* | |
157 | * This function will get called before each instruction | |
158 | * gets executed in execloop(). We use the coverage_dump tool | |
159 | * in legion to read the datafile. | |
160 | */ | |
161 | void | |
162 | dbg_coverage(simcpu_t *sp, uint32_t rawi) | |
163 | { | |
164 | extern uint32_t sim_atomic_add_32_nv(uint32_t *target, int32_t delta); | |
165 | int idx = 0; | |
166 | sparcv9_cpu_t *v9p = (sparcv9_cpu_t *)(sp->specificp); | |
167 | ||
168 | /* | |
169 | * Only store data when %pc is in Hypervisor and it is in range | |
170 | * XXX FIXME: we could parse the state from the config file. | |
171 | */ | |
172 | if ((v9p->state != V9_HyperPriv) || | |
173 | (sp->pc <= start_pc) || (sp->pc >= end_pc)) { | |
174 | return; | |
175 | } | |
176 | ||
177 | idx = ((sp->pc - start_pc) / 4); | |
178 | ||
179 | /* Increment counter and copy instn into buffer once */ | |
180 | if (sim_atomic_add_32_nv(&(coverage_bufp[idx].count), 1) == 1) { | |
181 | coverage_bufp[idx].pc = sp->pc; | |
182 | coverage_bufp[idx].rawi = rawi; | |
183 | } | |
184 | } | |
185 | ||
186 | void | |
187 | dbg_coverage_dump(void) | |
188 | { | |
189 | printf("\ndbg_coverage_dump: caled with start=0x%llx, end=0x%llx", | |
190 | start_pc, end_pc); | |
191 | printf("\nuse legion's coverage_dump tool to read the data file"); | |
192 | } |