xref: /openbmc/qemu/tcg/perf.c (revision 327b75a4)
1*327b75a4SIlya Leoshkevich /*
2*327b75a4SIlya Leoshkevich  * Linux perf perf-<pid>.map and jit-<pid>.dump integration.
3*327b75a4SIlya Leoshkevich  *
4*327b75a4SIlya Leoshkevich  * The jitdump spec can be found at [1].
5*327b75a4SIlya Leoshkevich  *
6*327b75a4SIlya Leoshkevich  * [1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/tools/perf/Documentation/jitdump-specification.txt
7*327b75a4SIlya Leoshkevich  *
8*327b75a4SIlya Leoshkevich  * SPDX-License-Identifier: GPL-2.0-or-later
9*327b75a4SIlya Leoshkevich  */
10*327b75a4SIlya Leoshkevich 
11*327b75a4SIlya Leoshkevich #include "qemu/osdep.h"
12*327b75a4SIlya Leoshkevich #include "elf.h"
13*327b75a4SIlya Leoshkevich #include "exec/target_page.h"
14*327b75a4SIlya Leoshkevich #include "exec/translation-block.h"
15*327b75a4SIlya Leoshkevich #include "qemu/timer.h"
16*327b75a4SIlya Leoshkevich #include "tcg/debuginfo.h"
17*327b75a4SIlya Leoshkevich #include "tcg/perf.h"
18*327b75a4SIlya Leoshkevich #include "tcg/tcg.h"
19*327b75a4SIlya Leoshkevich 
safe_fopen_w(const char * path)20*327b75a4SIlya Leoshkevich static FILE *safe_fopen_w(const char *path)
21*327b75a4SIlya Leoshkevich {
22*327b75a4SIlya Leoshkevich     int saved_errno;
23*327b75a4SIlya Leoshkevich     FILE *f;
24*327b75a4SIlya Leoshkevich     int fd;
25*327b75a4SIlya Leoshkevich 
26*327b75a4SIlya Leoshkevich     /* Delete the old file, if any. */
27*327b75a4SIlya Leoshkevich     unlink(path);
28*327b75a4SIlya Leoshkevich 
29*327b75a4SIlya Leoshkevich     /* Avoid symlink attacks by using O_CREAT | O_EXCL. */
30*327b75a4SIlya Leoshkevich     fd = open(path, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
31*327b75a4SIlya Leoshkevich     if (fd == -1) {
32*327b75a4SIlya Leoshkevich         return NULL;
33*327b75a4SIlya Leoshkevich     }
34*327b75a4SIlya Leoshkevich 
35*327b75a4SIlya Leoshkevich     /* Convert fd to FILE*. */
36*327b75a4SIlya Leoshkevich     f = fdopen(fd, "w");
37*327b75a4SIlya Leoshkevich     if (f == NULL) {
38*327b75a4SIlya Leoshkevich         saved_errno = errno;
39*327b75a4SIlya Leoshkevich         close(fd);
40*327b75a4SIlya Leoshkevich         errno = saved_errno;
41*327b75a4SIlya Leoshkevich         return NULL;
42*327b75a4SIlya Leoshkevich     }
43*327b75a4SIlya Leoshkevich 
44*327b75a4SIlya Leoshkevich     return f;
45*327b75a4SIlya Leoshkevich }
46*327b75a4SIlya Leoshkevich 
47*327b75a4SIlya Leoshkevich static FILE *perfmap;
48*327b75a4SIlya Leoshkevich 
perf_enable_perfmap(void)49*327b75a4SIlya Leoshkevich void perf_enable_perfmap(void)
50*327b75a4SIlya Leoshkevich {
51*327b75a4SIlya Leoshkevich     char map_file[32];
52*327b75a4SIlya Leoshkevich 
53*327b75a4SIlya Leoshkevich     snprintf(map_file, sizeof(map_file), "/tmp/perf-%d.map", getpid());
54*327b75a4SIlya Leoshkevich     perfmap = safe_fopen_w(map_file);
55*327b75a4SIlya Leoshkevich     if (perfmap == NULL) {
56*327b75a4SIlya Leoshkevich         warn_report("Could not open %s: %s, proceeding without perfmap",
57*327b75a4SIlya Leoshkevich                     map_file, strerror(errno));
58*327b75a4SIlya Leoshkevich     }
59*327b75a4SIlya Leoshkevich }
60*327b75a4SIlya Leoshkevich 
61*327b75a4SIlya Leoshkevich /* Get PC and size of code JITed for guest instruction #INSN. */
get_host_pc_size(uintptr_t * host_pc,uint16_t * host_size,const void * start,size_t insn)62*327b75a4SIlya Leoshkevich static void get_host_pc_size(uintptr_t *host_pc, uint16_t *host_size,
63*327b75a4SIlya Leoshkevich                              const void *start, size_t insn)
64*327b75a4SIlya Leoshkevich {
65*327b75a4SIlya Leoshkevich     uint16_t start_off = insn ? tcg_ctx->gen_insn_end_off[insn - 1] : 0;
66*327b75a4SIlya Leoshkevich 
67*327b75a4SIlya Leoshkevich     if (host_pc) {
68*327b75a4SIlya Leoshkevich         *host_pc = (uintptr_t)start + start_off;
69*327b75a4SIlya Leoshkevich     }
70*327b75a4SIlya Leoshkevich     if (host_size) {
71*327b75a4SIlya Leoshkevich         *host_size = tcg_ctx->gen_insn_end_off[insn] - start_off;
72*327b75a4SIlya Leoshkevich     }
73*327b75a4SIlya Leoshkevich }
74*327b75a4SIlya Leoshkevich 
pretty_symbol(const struct debuginfo_query * q,size_t * len)75*327b75a4SIlya Leoshkevich static const char *pretty_symbol(const struct debuginfo_query *q, size_t *len)
76*327b75a4SIlya Leoshkevich {
77*327b75a4SIlya Leoshkevich     static __thread char buf[64];
78*327b75a4SIlya Leoshkevich     int tmp;
79*327b75a4SIlya Leoshkevich 
80*327b75a4SIlya Leoshkevich     if (!q->symbol) {
81*327b75a4SIlya Leoshkevich         tmp = snprintf(buf, sizeof(buf), "guest-0x%"PRIx64, q->address);
82*327b75a4SIlya Leoshkevich         if (len) {
83*327b75a4SIlya Leoshkevich             *len = MIN(tmp + 1, sizeof(buf));
84*327b75a4SIlya Leoshkevich         }
85*327b75a4SIlya Leoshkevich         return buf;
86*327b75a4SIlya Leoshkevich     }
87*327b75a4SIlya Leoshkevich 
88*327b75a4SIlya Leoshkevich     if (!q->offset) {
89*327b75a4SIlya Leoshkevich         if (len) {
90*327b75a4SIlya Leoshkevich             *len = strlen(q->symbol) + 1;
91*327b75a4SIlya Leoshkevich         }
92*327b75a4SIlya Leoshkevich         return q->symbol;
93*327b75a4SIlya Leoshkevich     }
94*327b75a4SIlya Leoshkevich 
95*327b75a4SIlya Leoshkevich     tmp = snprintf(buf, sizeof(buf), "%s+0x%"PRIx64, q->symbol, q->offset);
96*327b75a4SIlya Leoshkevich     if (len) {
97*327b75a4SIlya Leoshkevich         *len = MIN(tmp + 1, sizeof(buf));
98*327b75a4SIlya Leoshkevich     }
99*327b75a4SIlya Leoshkevich     return buf;
100*327b75a4SIlya Leoshkevich }
101*327b75a4SIlya Leoshkevich 
write_perfmap_entry(const void * start,size_t insn,const struct debuginfo_query * q)102*327b75a4SIlya Leoshkevich static void write_perfmap_entry(const void *start, size_t insn,
103*327b75a4SIlya Leoshkevich                                 const struct debuginfo_query *q)
104*327b75a4SIlya Leoshkevich {
105*327b75a4SIlya Leoshkevich     uint16_t host_size;
106*327b75a4SIlya Leoshkevich     uintptr_t host_pc;
107*327b75a4SIlya Leoshkevich 
108*327b75a4SIlya Leoshkevich     get_host_pc_size(&host_pc, &host_size, start, insn);
109*327b75a4SIlya Leoshkevich     fprintf(perfmap, "%"PRIxPTR" %"PRIx16" %s\n",
110*327b75a4SIlya Leoshkevich             host_pc, host_size, pretty_symbol(q, NULL));
111*327b75a4SIlya Leoshkevich }
112*327b75a4SIlya Leoshkevich 
113*327b75a4SIlya Leoshkevich static FILE *jitdump;
114*327b75a4SIlya Leoshkevich static size_t perf_marker_size;
115*327b75a4SIlya Leoshkevich static void *perf_marker = MAP_FAILED;
116*327b75a4SIlya Leoshkevich 
117*327b75a4SIlya Leoshkevich #define JITHEADER_MAGIC 0x4A695444
118*327b75a4SIlya Leoshkevich #define JITHEADER_VERSION 1
119*327b75a4SIlya Leoshkevich 
120*327b75a4SIlya Leoshkevich struct jitheader {
121*327b75a4SIlya Leoshkevich     uint32_t magic;
122*327b75a4SIlya Leoshkevich     uint32_t version;
123*327b75a4SIlya Leoshkevich     uint32_t total_size;
124*327b75a4SIlya Leoshkevich     uint32_t elf_mach;
125*327b75a4SIlya Leoshkevich     uint32_t pad1;
126*327b75a4SIlya Leoshkevich     uint32_t pid;
127*327b75a4SIlya Leoshkevich     uint64_t timestamp;
128*327b75a4SIlya Leoshkevich     uint64_t flags;
129*327b75a4SIlya Leoshkevich };
130*327b75a4SIlya Leoshkevich 
131*327b75a4SIlya Leoshkevich enum jit_record_type {
132*327b75a4SIlya Leoshkevich     JIT_CODE_LOAD = 0,
133*327b75a4SIlya Leoshkevich     JIT_CODE_DEBUG_INFO = 2,
134*327b75a4SIlya Leoshkevich };
135*327b75a4SIlya Leoshkevich 
136*327b75a4SIlya Leoshkevich struct jr_prefix {
137*327b75a4SIlya Leoshkevich     uint32_t id;
138*327b75a4SIlya Leoshkevich     uint32_t total_size;
139*327b75a4SIlya Leoshkevich     uint64_t timestamp;
140*327b75a4SIlya Leoshkevich };
141*327b75a4SIlya Leoshkevich 
142*327b75a4SIlya Leoshkevich struct jr_code_load {
143*327b75a4SIlya Leoshkevich     struct jr_prefix p;
144*327b75a4SIlya Leoshkevich 
145*327b75a4SIlya Leoshkevich     uint32_t pid;
146*327b75a4SIlya Leoshkevich     uint32_t tid;
147*327b75a4SIlya Leoshkevich     uint64_t vma;
148*327b75a4SIlya Leoshkevich     uint64_t code_addr;
149*327b75a4SIlya Leoshkevich     uint64_t code_size;
150*327b75a4SIlya Leoshkevich     uint64_t code_index;
151*327b75a4SIlya Leoshkevich };
152*327b75a4SIlya Leoshkevich 
153*327b75a4SIlya Leoshkevich struct debug_entry {
154*327b75a4SIlya Leoshkevich     uint64_t addr;
155*327b75a4SIlya Leoshkevich     int lineno;
156*327b75a4SIlya Leoshkevich     int discrim;
157*327b75a4SIlya Leoshkevich     const char name[];
158*327b75a4SIlya Leoshkevich };
159*327b75a4SIlya Leoshkevich 
160*327b75a4SIlya Leoshkevich struct jr_code_debug_info {
161*327b75a4SIlya Leoshkevich     struct jr_prefix p;
162*327b75a4SIlya Leoshkevich 
163*327b75a4SIlya Leoshkevich     uint64_t code_addr;
164*327b75a4SIlya Leoshkevich     uint64_t nr_entry;
165*327b75a4SIlya Leoshkevich     struct debug_entry entries[];
166*327b75a4SIlya Leoshkevich };
167*327b75a4SIlya Leoshkevich 
get_e_machine(void)168*327b75a4SIlya Leoshkevich static uint32_t get_e_machine(void)
169*327b75a4SIlya Leoshkevich {
170*327b75a4SIlya Leoshkevich     Elf64_Ehdr elf_header;
171*327b75a4SIlya Leoshkevich     FILE *exe;
172*327b75a4SIlya Leoshkevich     size_t n;
173*327b75a4SIlya Leoshkevich 
174*327b75a4SIlya Leoshkevich     QEMU_BUILD_BUG_ON(offsetof(Elf32_Ehdr, e_machine) !=
175*327b75a4SIlya Leoshkevich                       offsetof(Elf64_Ehdr, e_machine));
176*327b75a4SIlya Leoshkevich 
177*327b75a4SIlya Leoshkevich     exe = fopen("/proc/self/exe", "r");
178*327b75a4SIlya Leoshkevich     if (exe == NULL) {
179*327b75a4SIlya Leoshkevich         return EM_NONE;
180*327b75a4SIlya Leoshkevich     }
181*327b75a4SIlya Leoshkevich 
182*327b75a4SIlya Leoshkevich     n = fread(&elf_header, sizeof(elf_header), 1, exe);
183*327b75a4SIlya Leoshkevich     fclose(exe);
184*327b75a4SIlya Leoshkevich     if (n != 1) {
185*327b75a4SIlya Leoshkevich         return EM_NONE;
186*327b75a4SIlya Leoshkevich     }
187*327b75a4SIlya Leoshkevich 
188*327b75a4SIlya Leoshkevich     return elf_header.e_machine;
189*327b75a4SIlya Leoshkevich }
190*327b75a4SIlya Leoshkevich 
perf_enable_jitdump(void)191*327b75a4SIlya Leoshkevich void perf_enable_jitdump(void)
192*327b75a4SIlya Leoshkevich {
193*327b75a4SIlya Leoshkevich     struct jitheader header;
194*327b75a4SIlya Leoshkevich     char jitdump_file[32];
195*327b75a4SIlya Leoshkevich 
196*327b75a4SIlya Leoshkevich     if (!use_rt_clock) {
197*327b75a4SIlya Leoshkevich         warn_report("CLOCK_MONOTONIC is not available, proceeding without jitdump");
198*327b75a4SIlya Leoshkevich         return;
199*327b75a4SIlya Leoshkevich     }
200*327b75a4SIlya Leoshkevich 
201*327b75a4SIlya Leoshkevich     snprintf(jitdump_file, sizeof(jitdump_file), "jit-%d.dump", getpid());
202*327b75a4SIlya Leoshkevich     jitdump = safe_fopen_w(jitdump_file);
203*327b75a4SIlya Leoshkevich     if (jitdump == NULL) {
204*327b75a4SIlya Leoshkevich         warn_report("Could not open %s: %s, proceeding without jitdump",
205*327b75a4SIlya Leoshkevich                     jitdump_file, strerror(errno));
206*327b75a4SIlya Leoshkevich         return;
207*327b75a4SIlya Leoshkevich     }
208*327b75a4SIlya Leoshkevich 
209*327b75a4SIlya Leoshkevich     /*
210*327b75a4SIlya Leoshkevich      * `perf inject` will see that the mapped file name in the corresponding
211*327b75a4SIlya Leoshkevich      * PERF_RECORD_MMAP or PERF_RECORD_MMAP2 event is of the form jit-%d.dump
212*327b75a4SIlya Leoshkevich      * and will process it as a jitdump file.
213*327b75a4SIlya Leoshkevich      */
214*327b75a4SIlya Leoshkevich     perf_marker_size = qemu_real_host_page_size();
215*327b75a4SIlya Leoshkevich     perf_marker = mmap(NULL, perf_marker_size, PROT_READ | PROT_EXEC,
216*327b75a4SIlya Leoshkevich                        MAP_PRIVATE, fileno(jitdump), 0);
217*327b75a4SIlya Leoshkevich     if (perf_marker == MAP_FAILED) {
218*327b75a4SIlya Leoshkevich         warn_report("Could not map %s: %s, proceeding without jitdump",
219*327b75a4SIlya Leoshkevich                     jitdump_file, strerror(errno));
220*327b75a4SIlya Leoshkevich         fclose(jitdump);
221*327b75a4SIlya Leoshkevich         jitdump = NULL;
222*327b75a4SIlya Leoshkevich         return;
223*327b75a4SIlya Leoshkevich     }
224*327b75a4SIlya Leoshkevich 
225*327b75a4SIlya Leoshkevich     header.magic = JITHEADER_MAGIC;
226*327b75a4SIlya Leoshkevich     header.version = JITHEADER_VERSION;
227*327b75a4SIlya Leoshkevich     header.total_size = sizeof(header);
228*327b75a4SIlya Leoshkevich     header.elf_mach = get_e_machine();
229*327b75a4SIlya Leoshkevich     header.pad1 = 0;
230*327b75a4SIlya Leoshkevich     header.pid = getpid();
231*327b75a4SIlya Leoshkevich     header.timestamp = get_clock();
232*327b75a4SIlya Leoshkevich     header.flags = 0;
233*327b75a4SIlya Leoshkevich     fwrite(&header, sizeof(header), 1, jitdump);
234*327b75a4SIlya Leoshkevich }
235*327b75a4SIlya Leoshkevich 
perf_report_prologue(const void * start,size_t size)236*327b75a4SIlya Leoshkevich void perf_report_prologue(const void *start, size_t size)
237*327b75a4SIlya Leoshkevich {
238*327b75a4SIlya Leoshkevich     if (perfmap) {
239*327b75a4SIlya Leoshkevich         fprintf(perfmap, "%"PRIxPTR" %zx tcg-prologue-buffer\n",
240*327b75a4SIlya Leoshkevich                 (uintptr_t)start, size);
241*327b75a4SIlya Leoshkevich     }
242*327b75a4SIlya Leoshkevich }
243*327b75a4SIlya Leoshkevich 
244*327b75a4SIlya Leoshkevich /* Write a JIT_CODE_DEBUG_INFO jitdump entry. */
write_jr_code_debug_info(const void * start,const struct debuginfo_query * q,size_t icount)245*327b75a4SIlya Leoshkevich static void write_jr_code_debug_info(const void *start,
246*327b75a4SIlya Leoshkevich                                      const struct debuginfo_query *q,
247*327b75a4SIlya Leoshkevich                                      size_t icount)
248*327b75a4SIlya Leoshkevich {
249*327b75a4SIlya Leoshkevich     struct jr_code_debug_info rec;
250*327b75a4SIlya Leoshkevich     struct debug_entry ent;
251*327b75a4SIlya Leoshkevich     uintptr_t host_pc;
252*327b75a4SIlya Leoshkevich     int insn;
253*327b75a4SIlya Leoshkevich 
254*327b75a4SIlya Leoshkevich     /* Write the header. */
255*327b75a4SIlya Leoshkevich     rec.p.id = JIT_CODE_DEBUG_INFO;
256*327b75a4SIlya Leoshkevich     rec.p.total_size = sizeof(rec) + sizeof(ent) + 1;
257*327b75a4SIlya Leoshkevich     rec.p.timestamp = get_clock();
258*327b75a4SIlya Leoshkevich     rec.code_addr = (uintptr_t)start;
259*327b75a4SIlya Leoshkevich     rec.nr_entry = 1;
260*327b75a4SIlya Leoshkevich     for (insn = 0; insn < icount; insn++) {
261*327b75a4SIlya Leoshkevich         if (q[insn].file) {
262*327b75a4SIlya Leoshkevich             rec.p.total_size += sizeof(ent) + strlen(q[insn].file) + 1;
263*327b75a4SIlya Leoshkevich             rec.nr_entry++;
264*327b75a4SIlya Leoshkevich         }
265*327b75a4SIlya Leoshkevich     }
266*327b75a4SIlya Leoshkevich     fwrite(&rec, sizeof(rec), 1, jitdump);
267*327b75a4SIlya Leoshkevich 
268*327b75a4SIlya Leoshkevich     /* Write the main debug entries. */
269*327b75a4SIlya Leoshkevich     for (insn = 0; insn < icount; insn++) {
270*327b75a4SIlya Leoshkevich         if (q[insn].file) {
271*327b75a4SIlya Leoshkevich             get_host_pc_size(&host_pc, NULL, start, insn);
272*327b75a4SIlya Leoshkevich             ent.addr = host_pc;
273*327b75a4SIlya Leoshkevich             ent.lineno = q[insn].line;
274*327b75a4SIlya Leoshkevich             ent.discrim = 0;
275*327b75a4SIlya Leoshkevich             fwrite(&ent, sizeof(ent), 1, jitdump);
276*327b75a4SIlya Leoshkevich             fwrite(q[insn].file, strlen(q[insn].file) + 1, 1, jitdump);
277*327b75a4SIlya Leoshkevich         }
278*327b75a4SIlya Leoshkevich     }
279*327b75a4SIlya Leoshkevich 
280*327b75a4SIlya Leoshkevich     /* Write the trailing debug_entry. */
281*327b75a4SIlya Leoshkevich     ent.addr = (uintptr_t)start + tcg_ctx->gen_insn_end_off[icount - 1];
282*327b75a4SIlya Leoshkevich     ent.lineno = 0;
283*327b75a4SIlya Leoshkevich     ent.discrim = 0;
284*327b75a4SIlya Leoshkevich     fwrite(&ent, sizeof(ent), 1, jitdump);
285*327b75a4SIlya Leoshkevich     fwrite("", 1, 1, jitdump);
286*327b75a4SIlya Leoshkevich }
287*327b75a4SIlya Leoshkevich 
288*327b75a4SIlya Leoshkevich /* Write a JIT_CODE_LOAD jitdump entry. */
write_jr_code_load(const void * start,uint16_t host_size,const struct debuginfo_query * q)289*327b75a4SIlya Leoshkevich static void write_jr_code_load(const void *start, uint16_t host_size,
290*327b75a4SIlya Leoshkevich                                const struct debuginfo_query *q)
291*327b75a4SIlya Leoshkevich {
292*327b75a4SIlya Leoshkevich     static uint64_t code_index;
293*327b75a4SIlya Leoshkevich     struct jr_code_load rec;
294*327b75a4SIlya Leoshkevich     const char *symbol;
295*327b75a4SIlya Leoshkevich     size_t symbol_size;
296*327b75a4SIlya Leoshkevich 
297*327b75a4SIlya Leoshkevich     symbol = pretty_symbol(q, &symbol_size);
298*327b75a4SIlya Leoshkevich     rec.p.id = JIT_CODE_LOAD;
299*327b75a4SIlya Leoshkevich     rec.p.total_size = sizeof(rec) + symbol_size + host_size;
300*327b75a4SIlya Leoshkevich     rec.p.timestamp = get_clock();
301*327b75a4SIlya Leoshkevich     rec.pid = getpid();
302*327b75a4SIlya Leoshkevich     rec.tid = qemu_get_thread_id();
303*327b75a4SIlya Leoshkevich     rec.vma = (uintptr_t)start;
304*327b75a4SIlya Leoshkevich     rec.code_addr = (uintptr_t)start;
305*327b75a4SIlya Leoshkevich     rec.code_size = host_size;
306*327b75a4SIlya Leoshkevich     rec.code_index = code_index++;
307*327b75a4SIlya Leoshkevich     fwrite(&rec, sizeof(rec), 1, jitdump);
308*327b75a4SIlya Leoshkevich     fwrite(symbol, symbol_size, 1, jitdump);
309*327b75a4SIlya Leoshkevich     fwrite(start, host_size, 1, jitdump);
310*327b75a4SIlya Leoshkevich }
311*327b75a4SIlya Leoshkevich 
perf_report_code(uint64_t guest_pc,TranslationBlock * tb,const void * start)312*327b75a4SIlya Leoshkevich void perf_report_code(uint64_t guest_pc, TranslationBlock *tb,
313*327b75a4SIlya Leoshkevich                       const void *start)
314*327b75a4SIlya Leoshkevich {
315*327b75a4SIlya Leoshkevich     struct debuginfo_query *q;
316*327b75a4SIlya Leoshkevich     size_t insn, start_words;
317*327b75a4SIlya Leoshkevich     uint64_t *gen_insn_data;
318*327b75a4SIlya Leoshkevich 
319*327b75a4SIlya Leoshkevich     if (!perfmap && !jitdump) {
320*327b75a4SIlya Leoshkevich         return;
321*327b75a4SIlya Leoshkevich     }
322*327b75a4SIlya Leoshkevich 
323*327b75a4SIlya Leoshkevich     q = g_try_malloc0_n(tb->icount, sizeof(*q));
324*327b75a4SIlya Leoshkevich     if (!q) {
325*327b75a4SIlya Leoshkevich         return;
326*327b75a4SIlya Leoshkevich     }
327*327b75a4SIlya Leoshkevich 
328*327b75a4SIlya Leoshkevich     debuginfo_lock();
329*327b75a4SIlya Leoshkevich 
330*327b75a4SIlya Leoshkevich     /* Query debuginfo for each guest instruction. */
331*327b75a4SIlya Leoshkevich     gen_insn_data = tcg_ctx->gen_insn_data;
332*327b75a4SIlya Leoshkevich     start_words = tcg_ctx->insn_start_words;
333*327b75a4SIlya Leoshkevich 
334*327b75a4SIlya Leoshkevich     for (insn = 0; insn < tb->icount; insn++) {
335*327b75a4SIlya Leoshkevich         /* FIXME: This replicates the restore_state_to_opc() logic. */
336*327b75a4SIlya Leoshkevich         q[insn].address = gen_insn_data[insn * start_words + 0];
337*327b75a4SIlya Leoshkevich         if (tb_cflags(tb) & CF_PCREL) {
338*327b75a4SIlya Leoshkevich             q[insn].address |= (guest_pc & qemu_target_page_mask());
339*327b75a4SIlya Leoshkevich         }
340*327b75a4SIlya Leoshkevich         q[insn].flags = DEBUGINFO_SYMBOL | (jitdump ? DEBUGINFO_LINE : 0);
341*327b75a4SIlya Leoshkevich     }
342*327b75a4SIlya Leoshkevich     debuginfo_query(q, tb->icount);
343*327b75a4SIlya Leoshkevich 
344*327b75a4SIlya Leoshkevich     /* Emit perfmap entries if needed. */
345*327b75a4SIlya Leoshkevich     if (perfmap) {
346*327b75a4SIlya Leoshkevich         flockfile(perfmap);
347*327b75a4SIlya Leoshkevich         for (insn = 0; insn < tb->icount; insn++) {
348*327b75a4SIlya Leoshkevich             write_perfmap_entry(start, insn, &q[insn]);
349*327b75a4SIlya Leoshkevich         }
350*327b75a4SIlya Leoshkevich         funlockfile(perfmap);
351*327b75a4SIlya Leoshkevich     }
352*327b75a4SIlya Leoshkevich 
353*327b75a4SIlya Leoshkevich     /* Emit jitdump entries if needed. */
354*327b75a4SIlya Leoshkevich     if (jitdump) {
355*327b75a4SIlya Leoshkevich         flockfile(jitdump);
356*327b75a4SIlya Leoshkevich         write_jr_code_debug_info(start, q, tb->icount);
357*327b75a4SIlya Leoshkevich         write_jr_code_load(start, tcg_ctx->gen_insn_end_off[tb->icount - 1],
358*327b75a4SIlya Leoshkevich                            q);
359*327b75a4SIlya Leoshkevich         funlockfile(jitdump);
360*327b75a4SIlya Leoshkevich     }
361*327b75a4SIlya Leoshkevich 
362*327b75a4SIlya Leoshkevich     debuginfo_unlock();
363*327b75a4SIlya Leoshkevich     g_free(q);
364*327b75a4SIlya Leoshkevich }
365*327b75a4SIlya Leoshkevich 
perf_exit(void)366*327b75a4SIlya Leoshkevich void perf_exit(void)
367*327b75a4SIlya Leoshkevich {
368*327b75a4SIlya Leoshkevich     if (perfmap) {
369*327b75a4SIlya Leoshkevich         fclose(perfmap);
370*327b75a4SIlya Leoshkevich         perfmap = NULL;
371*327b75a4SIlya Leoshkevich     }
372*327b75a4SIlya Leoshkevich 
373*327b75a4SIlya Leoshkevich     if (perf_marker != MAP_FAILED) {
374*327b75a4SIlya Leoshkevich         munmap(perf_marker, perf_marker_size);
375*327b75a4SIlya Leoshkevich         perf_marker = MAP_FAILED;
376*327b75a4SIlya Leoshkevich     }
377*327b75a4SIlya Leoshkevich 
378*327b75a4SIlya Leoshkevich     if (jitdump) {
379*327b75a4SIlya Leoshkevich         fclose(jitdump);
380*327b75a4SIlya Leoshkevich         jitdump = NULL;
381*327b75a4SIlya Leoshkevich     }
382*327b75a4SIlya Leoshkevich }
383