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