~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/perf/util/genelf_debug.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0-only
  2 /*
  3  * genelf_debug.c
  4  * Copyright (C) 2015, Google, Inc
  5  *
  6  * Contributed by:
  7  *      Stephane Eranian <eranian@google.com>
  8  *
  9  * based on GPLv2 source code from Oprofile
 10  * @remark Copyright 2007 OProfile authors
 11  * @author Philippe Elie
 12  */
 13 #include <linux/compiler.h>
 14 #include <linux/zalloc.h>
 15 #include <sys/types.h>
 16 #include <stdio.h>
 17 #include <getopt.h>
 18 #include <stddef.h>
 19 #include <libelf.h>
 20 #include <string.h>
 21 #include <stdlib.h>
 22 #include <inttypes.h>
 23 #include <limits.h>
 24 #include <fcntl.h>
 25 #include <err.h>
 26 #include <dwarf.h>
 27 
 28 #include "genelf.h"
 29 #include "../util/jitdump.h"
 30 
 31 #define BUFFER_EXT_DFL_SIZE     (4 * 1024)
 32 
 33 typedef uint32_t uword;
 34 typedef uint16_t uhalf;
 35 typedef int32_t  sword;
 36 typedef int16_t  shalf;
 37 typedef uint8_t  ubyte;
 38 typedef int8_t   sbyte;
 39 
 40 struct buffer_ext {
 41         size_t cur_pos;
 42         size_t max_sz;
 43         void *data;
 44 };
 45 
 46 static void
 47 buffer_ext_dump(struct buffer_ext *be, const char *msg)
 48 {
 49         size_t i;
 50         warnx("DUMP for %s", msg);
 51         for (i = 0 ; i < be->cur_pos; i++)
 52                 warnx("%4zu 0x%02x", i, (((char *)be->data)[i]) & 0xff);
 53 }
 54 
 55 static inline int
 56 buffer_ext_add(struct buffer_ext *be, void *addr, size_t sz)
 57 {
 58         void *tmp;
 59         size_t be_sz = be->max_sz;
 60 
 61 retry:
 62         if ((be->cur_pos + sz) < be_sz) {
 63                 memcpy(be->data + be->cur_pos, addr, sz);
 64                 be->cur_pos += sz;
 65                 return 0;
 66         }
 67 
 68         if (!be_sz)
 69                 be_sz = BUFFER_EXT_DFL_SIZE;
 70         else
 71                 be_sz <<= 1;
 72 
 73         tmp = realloc(be->data, be_sz);
 74         if (!tmp)
 75                 return -1;
 76 
 77         be->data   = tmp;
 78         be->max_sz = be_sz;
 79 
 80         goto retry;
 81 }
 82 
 83 static void
 84 buffer_ext_init(struct buffer_ext *be)
 85 {
 86         be->data = NULL;
 87         be->cur_pos = 0;
 88         be->max_sz = 0;
 89 }
 90 
 91 static void
 92 buffer_ext_exit(struct buffer_ext *be)
 93 {
 94         zfree(&be->data);
 95 }
 96 
 97 static inline size_t
 98 buffer_ext_size(struct buffer_ext *be)
 99 {
100         return be->cur_pos;
101 }
102 
103 static inline void *
104 buffer_ext_addr(struct buffer_ext *be)
105 {
106         return be->data;
107 }
108 
109 struct debug_line_header {
110         // Not counting this field
111         uword total_length;
112         // version number (2 currently)
113         uhalf version;
114         // relative offset from next field to
115         // program statement
116         uword prolog_length;
117         ubyte minimum_instruction_length;
118         ubyte default_is_stmt;
119         // line_base - see DWARF 2 specs
120         sbyte line_base;
121         // line_range - see DWARF 2 specs
122         ubyte line_range;
123         // number of opcode + 1
124         ubyte opcode_base;
125         /* follow the array of opcode args nr: ubytes [nr_opcode_base] */
126         /* follow the search directories index, zero terminated string
127          * terminated by an empty string.
128          */
129         /* follow an array of { filename, LEB128, LEB128, LEB128 }, first is
130          * the directory index entry, 0 means current directory, then mtime
131          * and filesize, last entry is followed by en empty string.
132          */
133         /* follow the first program statement */
134 } __packed;
135 
136 /* DWARF 2 spec talk only about one possible compilation unit header while
137  * binutils can handle two flavours of dwarf 2, 32 and 64 bits, this is not
138  * related to the used arch, an ELF 32 can hold more than 4 Go of debug
139  * information. For now we handle only DWARF 2 32 bits comp unit. It'll only
140  * become a problem if we generate more than 4GB of debug information.
141  */
142 struct compilation_unit_header {
143         uword total_length;
144         uhalf version;
145         uword debug_abbrev_offset;
146         ubyte pointer_size;
147 } __packed;
148 
149 #define DW_LNS_num_opcode (DW_LNS_set_isa + 1)
150 
151 /* field filled at run time are marked with -1 */
152 static struct debug_line_header const default_debug_line_header = {
153         .total_length = -1,
154         .version = 2,
155         .prolog_length = -1,
156         .minimum_instruction_length = 1,        /* could be better when min instruction size != 1 */
157         .default_is_stmt = 1,   /* we don't take care about basic block */
158         .line_base = -5,        /* sensible value for line base ... */
159         .line_range = -14,     /* ... and line range are guessed statically */
160         .opcode_base = DW_LNS_num_opcode
161 };
162 
163 static ubyte standard_opcode_length[] =
164 {
165         0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1
166 };
167 #if 0
168 {
169         [DW_LNS_advance_pc]   = 1,
170         [DW_LNS_advance_line] = 1,
171         [DW_LNS_set_file] =  1,
172         [DW_LNS_set_column] = 1,
173         [DW_LNS_fixed_advance_pc] = 1,
174         [DW_LNS_set_isa] = 1,
175 };
176 #endif
177 
178 /* field filled at run time are marked with -1 */
179 static struct compilation_unit_header default_comp_unit_header = {
180         .total_length = -1,
181         .version = 2,
182         .debug_abbrev_offset = 0,     /* we reuse the same abbrev entries for all comp unit */
183         .pointer_size = sizeof(void *)
184 };
185 
186 static void emit_uword(struct buffer_ext *be, uword data)
187 {
188         buffer_ext_add(be, &data, sizeof(uword));
189 }
190 
191 static void emit_string(struct buffer_ext *be, const char *s)
192 {
193         buffer_ext_add(be, (void *)s, strlen(s) + 1);
194 }
195 
196 static void emit_unsigned_LEB128(struct buffer_ext *be,
197                                  unsigned long data)
198 {
199         do {
200                 ubyte cur = data & 0x7F;
201                 data >>= 7;
202                 if (data)
203                         cur |= 0x80;
204                 buffer_ext_add(be, &cur, 1);
205         } while (data);
206 }
207 
208 static void emit_signed_LEB128(struct buffer_ext *be, long data)
209 {
210         int more = 1;
211         int negative = data < 0;
212         int size = sizeof(long) * CHAR_BIT;
213         while (more) {
214                 ubyte cur = data & 0x7F;
215                 data >>= 7;
216                 if (negative)
217                         data |= - (1 << (size - 7));
218                 if ((data == 0 && !(cur & 0x40)) ||
219                     (data == -1l && (cur & 0x40)))
220                         more = 0;
221                 else
222                         cur |= 0x80;
223                 buffer_ext_add(be, &cur, 1);
224         }
225 }
226 
227 static void emit_extended_opcode(struct buffer_ext *be, ubyte opcode,
228                                  void *data, size_t data_len)
229 {
230         buffer_ext_add(be, (char *)"", 1);
231 
232         emit_unsigned_LEB128(be, data_len + 1);
233 
234         buffer_ext_add(be, &opcode, 1);
235         buffer_ext_add(be, data, data_len);
236 }
237 
238 static void emit_opcode(struct buffer_ext *be, ubyte opcode)
239 {
240         buffer_ext_add(be, &opcode, 1);
241 }
242 
243 static void emit_opcode_signed(struct buffer_ext  *be,
244                                ubyte opcode, long data)
245 {
246         buffer_ext_add(be, &opcode, 1);
247         emit_signed_LEB128(be, data);
248 }
249 
250 static void emit_opcode_unsigned(struct buffer_ext *be, ubyte opcode,
251                                  unsigned long data)
252 {
253         buffer_ext_add(be, &opcode, 1);
254         emit_unsigned_LEB128(be, data);
255 }
256 
257 static void emit_advance_pc(struct buffer_ext *be, unsigned long delta_pc)
258 {
259         emit_opcode_unsigned(be, DW_LNS_advance_pc, delta_pc);
260 }
261 
262 static void emit_advance_lineno(struct buffer_ext  *be, long delta_lineno)
263 {
264         emit_opcode_signed(be, DW_LNS_advance_line, delta_lineno);
265 }
266 
267 static void emit_lne_end_of_sequence(struct buffer_ext *be)
268 {
269         emit_extended_opcode(be, DW_LNE_end_sequence, NULL, 0);
270 }
271 
272 static void emit_set_file(struct buffer_ext *be, unsigned long idx)
273 {
274         emit_opcode_unsigned(be, DW_LNS_set_file, idx);
275 }
276 
277 static void emit_lne_define_filename(struct buffer_ext *be,
278                                      const char *filename)
279 {
280         buffer_ext_add(be, (void *)"", 1);
281 
282         /* LNE field, strlen(filename) + zero termination, 3 bytes for: the dir entry, timestamp, filesize */
283         emit_unsigned_LEB128(be, strlen(filename) + 5);
284         emit_opcode(be, DW_LNE_define_file);
285         emit_string(be, filename);
286         /* directory index 0=do not know */
287         emit_unsigned_LEB128(be, 0);
288         /* last modification date on file 0=do not know */
289         emit_unsigned_LEB128(be, 0);
290         /* filesize 0=do not know */
291         emit_unsigned_LEB128(be, 0);
292 }
293 
294 static void emit_lne_set_address(struct buffer_ext *be,
295                                  void *address)
296 {
297         emit_extended_opcode(be, DW_LNE_set_address, &address, sizeof(unsigned long));
298 }
299 
300 static ubyte get_special_opcode(struct debug_entry *ent,
301                                 unsigned int last_line,
302                                 unsigned long last_vma)
303 {
304         unsigned int temp;
305         unsigned long delta_addr;
306 
307         /*
308          * delta from line_base
309          */
310         temp = (ent->lineno - last_line) - default_debug_line_header.line_base;
311 
312         if (temp >= default_debug_line_header.line_range)
313                 return 0;
314 
315         /*
316          * delta of addresses
317          */
318         delta_addr = (ent->addr - last_vma) / default_debug_line_header.minimum_instruction_length;
319 
320         /* This is not sufficient to ensure opcode will be in [0-256] but
321          * sufficient to ensure when summing with the delta lineno we will
322          * not overflow the unsigned long opcode */
323 
324         if (delta_addr <= 256 / default_debug_line_header.line_range) {
325                 unsigned long opcode = temp +
326                         (delta_addr * default_debug_line_header.line_range) +
327                         default_debug_line_header.opcode_base;
328 
329                 return opcode <= 255 ? opcode : 0;
330         }
331         return 0;
332 }
333 
334 static void emit_lineno_info(struct buffer_ext *be,
335                              struct debug_entry *ent, size_t nr_entry,
336                              unsigned long code_addr)
337 {
338         size_t i;
339 
340         /* as described in the jitdump format */
341         const char repeated_name_marker[] = {'\xff', '\0'};
342 
343         /*
344          * Machine state at start of a statement program
345          * address = 0
346          * file    = 1
347          * line    = 1
348          * column  = 0
349          * is_stmt = default_is_stmt as given in the debug_line_header
350          * basic block = 0
351          * end sequence = 0
352          */
353 
354         /* start state of the state machine we take care of */
355         unsigned long last_vma = 0;
356         char const  *cur_filename = NULL;
357         unsigned long cur_file_idx = 0;
358         int last_line = 1;
359 
360         emit_lne_set_address(be, (void *)code_addr);
361 
362         for (i = 0; i < nr_entry; i++, ent = debug_entry_next(ent)) {
363                 int need_copy = 0;
364                 ubyte special_opcode;
365 
366                 /*
367                  * check if filename changed, if so add it
368                  */
369                 if ((!cur_filename || strcmp(cur_filename, ent->name)) &&
370                         strcmp(repeated_name_marker, ent->name)) {
371                         emit_lne_define_filename(be, ent->name);
372                         cur_filename = ent->name;
373                         emit_set_file(be, ++cur_file_idx);
374                         need_copy = 1;
375                 }
376 
377                 special_opcode = get_special_opcode(ent, last_line, last_vma);
378                 if (special_opcode != 0) {
379                         last_line = ent->lineno;
380                         last_vma  = ent->addr;
381                         emit_opcode(be, special_opcode);
382                 } else {
383                         /*
384                          * lines differ, emit line delta
385                          */
386                         if (last_line != ent->lineno) {
387                                 emit_advance_lineno(be, ent->lineno - last_line);
388                                 last_line = ent->lineno;
389                                 need_copy = 1;
390                         }
391                         /*
392                          * addresses differ, emit address delta
393                          */
394                         if (last_vma != ent->addr) {
395                                 emit_advance_pc(be, ent->addr - last_vma);
396                                 last_vma = ent->addr;
397                                 need_copy = 1;
398                         }
399                         /*
400                          * add new row to matrix
401                          */
402                         if (need_copy)
403                                 emit_opcode(be, DW_LNS_copy);
404                 }
405         }
406 }
407 
408 static void add_debug_line(struct buffer_ext *be,
409         struct debug_entry *ent, size_t nr_entry,
410         unsigned long code_addr)
411 {
412         struct debug_line_header * dbg_header;
413         size_t old_size;
414 
415         old_size = buffer_ext_size(be);
416 
417         buffer_ext_add(be, (void *)&default_debug_line_header,
418                  sizeof(default_debug_line_header));
419 
420         buffer_ext_add(be, &standard_opcode_length,  sizeof(standard_opcode_length));
421 
422         // empty directory entry
423         buffer_ext_add(be, (void *)"", 1);
424 
425         // empty filename directory
426         buffer_ext_add(be, (void *)"", 1);
427 
428         dbg_header = buffer_ext_addr(be) + old_size;
429         dbg_header->prolog_length = (buffer_ext_size(be) - old_size) -
430                 offsetof(struct debug_line_header, minimum_instruction_length);
431 
432         emit_lineno_info(be, ent, nr_entry, code_addr);
433 
434         emit_lne_end_of_sequence(be);
435 
436         dbg_header = buffer_ext_addr(be) + old_size;
437         dbg_header->total_length = (buffer_ext_size(be) - old_size) -
438                 offsetof(struct debug_line_header, version);
439 }
440 
441 static void
442 add_debug_abbrev(struct buffer_ext *be)
443 {
444         emit_unsigned_LEB128(be, 1);
445         emit_unsigned_LEB128(be, DW_TAG_compile_unit);
446         emit_unsigned_LEB128(be, DW_CHILDREN_yes);
447         emit_unsigned_LEB128(be, DW_AT_stmt_list);
448         emit_unsigned_LEB128(be, DW_FORM_data4);
449         emit_unsigned_LEB128(be, 0);
450         emit_unsigned_LEB128(be, 0);
451         emit_unsigned_LEB128(be, 0);
452 }
453 
454 static void
455 add_compilation_unit(struct buffer_ext *be,
456                      size_t offset_debug_line)
457 {
458         struct compilation_unit_header *comp_unit_header;
459         size_t old_size = buffer_ext_size(be);
460 
461         buffer_ext_add(be, &default_comp_unit_header,
462                        sizeof(default_comp_unit_header));
463 
464         emit_unsigned_LEB128(be, 1);
465         emit_uword(be, offset_debug_line);
466 
467         comp_unit_header = buffer_ext_addr(be) + old_size;
468         comp_unit_header->total_length = (buffer_ext_size(be) - old_size) -
469                 offsetof(struct compilation_unit_header, version);
470 }
471 
472 static int
473 jit_process_debug_info(uint64_t code_addr,
474                        void *debug, int nr_debug_entries,
475                        struct buffer_ext *dl,
476                        struct buffer_ext *da,
477                        struct buffer_ext *di)
478 {
479         struct debug_entry *ent = debug;
480         int i;
481 
482         for (i = 0; i < nr_debug_entries; i++) {
483                 ent->addr = ent->addr - code_addr;
484                 ent = debug_entry_next(ent);
485         }
486         add_compilation_unit(di, buffer_ext_size(dl));
487         add_debug_line(dl, debug, nr_debug_entries, GEN_ELF_TEXT_OFFSET);
488         add_debug_abbrev(da);
489         if (0) buffer_ext_dump(da, "abbrev");
490 
491         return 0;
492 }
493 
494 int
495 jit_add_debug_info(Elf *e, uint64_t code_addr, void *debug, int nr_debug_entries)
496 {
497         Elf_Data *d;
498         Elf_Scn *scn;
499         Elf_Shdr *shdr;
500         struct buffer_ext dl, di, da;
501         int ret = -1;
502 
503         buffer_ext_init(&dl);
504         buffer_ext_init(&di);
505         buffer_ext_init(&da);
506 
507         if (jit_process_debug_info(code_addr, debug, nr_debug_entries, &dl, &da, &di))
508                 goto out;
509 
510         /*
511          * setup .debug_line section
512          */
513         scn = elf_newscn(e);
514         if (!scn) {
515                 warnx("cannot create section");
516                 goto out;
517         }
518 
519         d = elf_newdata(scn);
520         if (!d) {
521                 warnx("cannot get new data");
522                 goto out;
523         }
524 
525         d->d_align = 1;
526         d->d_off = 0LL;
527         d->d_buf = buffer_ext_addr(&dl);
528         d->d_type = ELF_T_BYTE;
529         d->d_size = buffer_ext_size(&dl);
530         d->d_version = EV_CURRENT;
531 
532         shdr = elf_getshdr(scn);
533         if (!shdr) {
534                 warnx("cannot get section header");
535                 goto out;
536         }
537 
538         shdr->sh_name = 52; /* .debug_line */
539         shdr->sh_type = SHT_PROGBITS;
540         shdr->sh_addr = 0; /* must be zero or == sh_offset -> dynamic object */
541         shdr->sh_flags = 0;
542         shdr->sh_entsize = 0;
543 
544         /*
545          * setup .debug_info section
546          */
547         scn = elf_newscn(e);
548         if (!scn) {
549                 warnx("cannot create section");
550                 goto out;
551         }
552 
553         d = elf_newdata(scn);
554         if (!d) {
555                 warnx("cannot get new data");
556                 goto out;
557         }
558 
559         d->d_align = 1;
560         d->d_off = 0LL;
561         d->d_buf = buffer_ext_addr(&di);
562         d->d_type = ELF_T_BYTE;
563         d->d_size = buffer_ext_size(&di);
564         d->d_version = EV_CURRENT;
565 
566         shdr = elf_getshdr(scn);
567         if (!shdr) {
568                 warnx("cannot get section header");
569                 goto out;
570         }
571 
572         shdr->sh_name = 64; /* .debug_info */
573         shdr->sh_type = SHT_PROGBITS;
574         shdr->sh_addr = 0; /* must be zero or == sh_offset -> dynamic object */
575         shdr->sh_flags = 0;
576         shdr->sh_entsize = 0;
577 
578         /*
579          * setup .debug_abbrev section
580          */
581         scn = elf_newscn(e);
582         if (!scn) {
583                 warnx("cannot create section");
584                 goto out;
585         }
586 
587         d = elf_newdata(scn);
588         if (!d) {
589                 warnx("cannot get new data");
590                 goto out;
591         }
592 
593         d->d_align = 1;
594         d->d_off = 0LL;
595         d->d_buf = buffer_ext_addr(&da);
596         d->d_type = ELF_T_BYTE;
597         d->d_size = buffer_ext_size(&da);
598         d->d_version = EV_CURRENT;
599 
600         shdr = elf_getshdr(scn);
601         if (!shdr) {
602                 warnx("cannot get section header");
603                 goto out;
604         }
605 
606         shdr->sh_name = 76; /* .debug_info */
607         shdr->sh_type = SHT_PROGBITS;
608         shdr->sh_addr = 0; /* must be zero or == sh_offset -> dynamic object */
609         shdr->sh_flags = 0;
610         shdr->sh_entsize = 0;
611 
612         /*
613          * now we update the ELF image with all the sections
614          */
615         if (elf_update(e, ELF_C_WRITE) < 0)
616                 warnx("elf_update debug failed");
617         else
618                 ret = 0;
619 
620 out:
621         buffer_ext_exit(&dl);
622         buffer_ext_exit(&di);
623         buffer_ext_exit(&da);
624         return ret;
625 }
626 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php