sigcdump 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: c7ecae7f81f6ea8257c8cede3efa1fc30328ece87d99f0e6e7e949c6bc1d7381
4
+ data.tar.gz: 16414972dc9b8cd428a7218eb9de2c29494bc892a65965970e28e2972f837b39
5
+ SHA512:
6
+ metadata.gz: 06272e5057743388ba089fbc5db399e77697162b01b0bf65a59869d75e0a33a2edca6ab2c84163694091bb12c09461ce0ad30bbf88fcaf794e3321280985d376
7
+ data.tar.gz: 33419cd6d433b20c8951063dc755ac06773965a03e0119910f8e54b7c8bcd30da33a754f9c17fd7cbc44aa674c62610776c65d044d298fd3b65d7cfdd2f75f08
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+ *.bundle
10
+ *.so
11
+ *.o
12
+ *.a
13
+ mkmf.log
14
+ .ruby-version
@@ -0,0 +1,3 @@
1
+ [submodule "ext/sigcdump/ruby"]
2
+ path = ext/sigcdump/ruby
3
+ url = https://github.com/ruby/ruby.git
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in sigcdump.gemspec
6
+ gemspec
7
+
8
+ gem 'pry'
@@ -0,0 +1,29 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ sigcdump (0.1.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ coderay (1.1.2)
10
+ method_source (0.9.2)
11
+ pry (0.12.2)
12
+ coderay (~> 1.1.0)
13
+ method_source (~> 0.9.0)
14
+ rake (13.0.1)
15
+ rake-compiler (1.0.8)
16
+ rake
17
+
18
+ PLATFORMS
19
+ ruby
20
+
21
+ DEPENDENCIES
22
+ bundler
23
+ pry
24
+ rake
25
+ rake-compiler
26
+ sigcdump!
27
+
28
+ BUNDLED WITH
29
+ 1.17.2
@@ -0,0 +1,56 @@
1
+ Ruby is copyrighted free software by Yukihiro Matsumoto <matz@netlab.jp>.
2
+ You can redistribute it and/or modify it under either the terms of the
3
+ 2-clause BSDL (see the file BSDL), or the conditions below:
4
+
5
+ 1. You may make and give away verbatim copies of the source form of the
6
+ software without restriction, provided that you duplicate all of the
7
+ original copyright notices and associated disclaimers.
8
+
9
+ 2. You may modify your copy of the software in any way, provided that
10
+ you do at least ONE of the following:
11
+
12
+ a. place your modifications in the Public Domain or otherwise
13
+ make them Freely Available, such as by posting said
14
+ modifications to Usenet or an equivalent medium, or by allowing
15
+ the author to include your modifications in the software.
16
+
17
+ b. use the modified software only within your corporation or
18
+ organization.
19
+
20
+ c. give non-standard binaries non-standard names, with
21
+ instructions on where to get the original software distribution.
22
+
23
+ d. make other distribution arrangements with the author.
24
+
25
+ 3. You may distribute the software in object code or binary form,
26
+ provided that you do at least ONE of the following:
27
+
28
+ a. distribute the binaries and library files of the software,
29
+ together with instructions (in the manual page or equivalent)
30
+ on where to get the original distribution.
31
+
32
+ b. accompany the distribution with the machine-readable source of
33
+ the software.
34
+
35
+ c. give non-standard binaries non-standard names, with
36
+ instructions on where to get the original software distribution.
37
+
38
+ d. make other distribution arrangements with the author.
39
+
40
+ 4. You may modify and include the part of the software into any other
41
+ software (possibly commercial). But some files in the distribution
42
+ are not written by the author, so that they are not under these terms.
43
+
44
+ For the list of those files and their copying conditions, see the
45
+ file LEGAL.
46
+
47
+ 5. The scripts and library files supplied as input to or produced as
48
+ output from the software do not automatically fall under the
49
+ copyright of the software, but belong to whomever generated them,
50
+ and may be sold commercially, and may be aggregated with this
51
+ software.
52
+
53
+ 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
54
+ IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
55
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
56
+ PURPOSE.
@@ -0,0 +1,37 @@
1
+ # Sigcdump
2
+
3
+ [Sigdump](https://github.com/frsyuki/sigdump) for C backtrace.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'sigcdump'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ NOTE: Unlike sigdump, this gem supports only CRuby.
18
+
19
+ ## Usage
20
+
21
+ ```rb
22
+ require 'sigcdump'
23
+ Sigcdump.setup('SIGCONT')
24
+ ```
25
+
26
+ or:
27
+
28
+ ```rb
29
+ # this calls Sigcdump.setup('SIGCONT')
30
+ require 'sigcdump/setup'
31
+ ```
32
+
33
+ Then `kill -TTIN <pid>` will show a C backtrace of a CRuby process.
34
+
35
+ ## License
36
+
37
+ The gem is available as open source under the terms of the [Ruby License](./LICENSE.txt).
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/extensiontask"
3
+
4
+ task :build => :compile
5
+
6
+ Rake::ExtensionTask.new("sigcdump") do |ext|
7
+ ext.lib_dir = "lib/sigcdump"
8
+ end
9
+
10
+ task :default => [:clobber, :compile, :spec]
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "sigcdump"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ require "pry"
11
+ Pry.start
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,16 @@
1
+ require 'mkmf'
2
+
3
+ ruby_dir = File.expand_path('./ruby', __dir__)
4
+ $INCFLAGS << " -I#{ruby_dir}"
5
+
6
+ $srcs = %w[
7
+ sigcdump.c
8
+ ]
9
+ %w[
10
+ addr2line.c
11
+ ].each do |c|
12
+ FileUtils.ln_s(File.join(ruby_dir, c), c, force: true)
13
+ $srcs << c
14
+ end
15
+
16
+ create_makefile('sigcdump/sigcdump')
@@ -0,0 +1,2663 @@
1
+ /**********************************************************************
2
+
3
+ addr2line.c -
4
+
5
+ $Author$
6
+
7
+ Copyright (C) 2010 Shinichiro Hamaji
8
+
9
+ **********************************************************************/
10
+
11
+ #if defined(__clang__)
12
+ #pragma clang diagnostic ignored "-Wgnu-empty-initializer"
13
+ #pragma clang diagnostic ignored "-Wgcc-compat"
14
+ #endif
15
+
16
+ #include "ruby/config.h"
17
+ #include "ruby/defines.h"
18
+ #include "ruby/missing.h"
19
+ #include "addr2line.h"
20
+
21
+ #include <stdio.h>
22
+ #include <errno.h>
23
+
24
+ #ifdef HAVE_LIBPROC_H
25
+ #include <libproc.h>
26
+ #endif
27
+
28
+ #ifdef HAVE_STDBOOL_H
29
+ #include <stdbool.h>
30
+ #else
31
+ #include "missing/stdbool.h"
32
+ #endif
33
+
34
+ #if defined(USE_ELF) || defined(HAVE_MACH_O_LOADER_H)
35
+
36
+ #include <fcntl.h>
37
+ #include <limits.h>
38
+ #include <stdio.h>
39
+ #include <stdint.h>
40
+ #include <stdlib.h>
41
+ #include <string.h>
42
+ #include <sys/mman.h>
43
+ #include <sys/types.h>
44
+ #include <sys/stat.h>
45
+ #include <unistd.h>
46
+
47
+ /* Make alloca work the best possible way. */
48
+ #ifdef __GNUC__
49
+ # ifndef alloca
50
+ # define alloca __builtin_alloca
51
+ # endif
52
+ #else
53
+ # ifdef HAVE_ALLOCA_H
54
+ # include <alloca.h>
55
+ # else
56
+ # ifdef _AIX
57
+ #pragma alloca
58
+ # else
59
+ # ifndef alloca /* predefined by HP cc +Olibcalls */
60
+ void *alloca();
61
+ # endif
62
+ # endif /* AIX */
63
+ # endif /* HAVE_ALLOCA_H */
64
+ #endif /* __GNUC__ */
65
+
66
+ #ifdef HAVE_DLADDR
67
+ # include <dlfcn.h>
68
+ #endif
69
+
70
+ #ifdef HAVE_MACH_O_LOADER_H
71
+ # include <crt_externs.h>
72
+ # include <mach-o/fat.h>
73
+ # include <mach-o/loader.h>
74
+ # include <mach-o/nlist.h>
75
+ # include <mach-o/stab.h>
76
+ #endif
77
+
78
+ #ifdef USE_ELF
79
+ # ifdef __OpenBSD__
80
+ # include <elf_abi.h>
81
+ # else
82
+ # include <elf.h>
83
+ # endif
84
+
85
+ #ifndef ElfW
86
+ # if SIZEOF_VOIDP == 8
87
+ # define ElfW(x) Elf64##_##x
88
+ # else
89
+ # define ElfW(x) Elf32##_##x
90
+ # endif
91
+ #endif
92
+ #ifndef ELF_ST_TYPE
93
+ # if SIZEOF_VOIDP == 8
94
+ # define ELF_ST_TYPE ELF64_ST_TYPE
95
+ # else
96
+ # define ELF_ST_TYPE ELF32_ST_TYPE
97
+ # endif
98
+ #endif
99
+ #endif
100
+
101
+ #ifdef SHF_COMPRESSED
102
+ # if defined(ELFCOMPRESS_ZLIB) && defined(HAVE_LIBZ)
103
+ /* FreeBSD 11.0 lacks ELFCOMPRESS_ZLIB */
104
+ # include <zlib.h>
105
+ # define SUPPORT_COMPRESSED_DEBUG_LINE
106
+ # endif
107
+ #else /* compatibility with glibc < 2.22 */
108
+ # define SHF_COMPRESSED 0
109
+ #endif
110
+
111
+ #ifndef PATH_MAX
112
+ #define PATH_MAX 4096
113
+ #endif
114
+
115
+ #define DW_LNS_copy 0x01
116
+ #define DW_LNS_advance_pc 0x02
117
+ #define DW_LNS_advance_line 0x03
118
+ #define DW_LNS_set_file 0x04
119
+ #define DW_LNS_set_column 0x05
120
+ #define DW_LNS_negate_stmt 0x06
121
+ #define DW_LNS_set_basic_block 0x07
122
+ #define DW_LNS_const_add_pc 0x08
123
+ #define DW_LNS_fixed_advance_pc 0x09
124
+ #define DW_LNS_set_prologue_end 0x0a /* DWARF3 */
125
+ #define DW_LNS_set_epilogue_begin 0x0b /* DWARF3 */
126
+ #define DW_LNS_set_isa 0x0c /* DWARF3 */
127
+
128
+ /* Line number extended opcode name. */
129
+ #define DW_LNE_end_sequence 0x01
130
+ #define DW_LNE_set_address 0x02
131
+ #define DW_LNE_define_file 0x03
132
+ #define DW_LNE_set_discriminator 0x04 /* DWARF4 */
133
+
134
+ PRINTF_ARGS(static int kprintf(const char *fmt, ...), 1, 2);
135
+
136
+ typedef struct line_info {
137
+ const char *dirname;
138
+ const char *filename;
139
+ const char *path; /* object path */
140
+ int line;
141
+
142
+ uintptr_t base_addr;
143
+ uintptr_t saddr;
144
+ const char *sname; /* function name */
145
+
146
+ struct line_info *next;
147
+ } line_info_t;
148
+
149
+ struct dwarf_section {
150
+ char *ptr;
151
+ size_t size;
152
+ uint64_t flags;
153
+ };
154
+
155
+ typedef struct obj_info {
156
+ const char *path; /* object path */
157
+ char *mapped;
158
+ size_t mapped_size;
159
+ void *uncompressed;
160
+ uintptr_t base_addr;
161
+ uintptr_t vmaddr;
162
+ struct dwarf_section debug_abbrev;
163
+ struct dwarf_section debug_info;
164
+ struct dwarf_section debug_line;
165
+ struct dwarf_section debug_ranges;
166
+ struct dwarf_section debug_str;
167
+ struct obj_info *next;
168
+ } obj_info_t;
169
+
170
+ #define DWARF_SECTION_COUNT 5
171
+
172
+ static struct dwarf_section *
173
+ obj_dwarf_section_at(obj_info_t *obj, int n)
174
+ {
175
+ struct dwarf_section *ary[] = {
176
+ &obj->debug_abbrev,
177
+ &obj->debug_info,
178
+ &obj->debug_line,
179
+ &obj->debug_ranges,
180
+ &obj->debug_str
181
+ };
182
+ if (n < 0 || DWARF_SECTION_COUNT <= n) {
183
+ abort();
184
+ }
185
+ return ary[n];
186
+ }
187
+
188
+ struct debug_section_definition {
189
+ const char *name;
190
+ struct dwarf_section *dwarf;
191
+ };
192
+
193
+ /* Avoid consuming stack as this module may be used from signal handler */
194
+ static char binary_filename[PATH_MAX + 1];
195
+
196
+ static unsigned long
197
+ uleb128(char **p)
198
+ {
199
+ unsigned long r = 0;
200
+ int s = 0;
201
+ for (;;) {
202
+ unsigned char b = *(unsigned char *)(*p)++;
203
+ if (b < 0x80) {
204
+ r += (unsigned long)b << s;
205
+ break;
206
+ }
207
+ r += (b & 0x7f) << s;
208
+ s += 7;
209
+ }
210
+ return r;
211
+ }
212
+
213
+ static long
214
+ sleb128(char **p)
215
+ {
216
+ long r = 0;
217
+ int s = 0;
218
+ for (;;) {
219
+ unsigned char b = *(unsigned char *)(*p)++;
220
+ if (b < 0x80) {
221
+ if (b & 0x40) {
222
+ r -= (0x80 - b) << s;
223
+ }
224
+ else {
225
+ r += (b & 0x3f) << s;
226
+ }
227
+ break;
228
+ }
229
+ r += (b & 0x7f) << s;
230
+ s += 7;
231
+ }
232
+ return r;
233
+ }
234
+
235
+ static const char *
236
+ get_nth_dirname(unsigned long dir, char *p)
237
+ {
238
+ if (!dir--) {
239
+ return "";
240
+ }
241
+ while (dir--) {
242
+ while (*p) p++;
243
+ p++;
244
+ if (!*p) {
245
+ kprintf("Unexpected directory number %lu in %s\n",
246
+ dir, binary_filename);
247
+ return "";
248
+ }
249
+ }
250
+ return p;
251
+ }
252
+
253
+ static void
254
+ fill_filename(int file, char *include_directories, char *filenames, line_info_t *line, obj_info_t *obj)
255
+ {
256
+ int i;
257
+ char *p = filenames;
258
+ char *filename;
259
+ unsigned long dir;
260
+ for (i = 1; i <= file; i++) {
261
+ filename = p;
262
+ if (!*p) {
263
+ /* Need to output binary file name? */
264
+ kprintf("Unexpected file number %d in %s at %tx\n",
265
+ file, binary_filename, filenames - obj->mapped);
266
+ return;
267
+ }
268
+ while (*p) p++;
269
+ p++;
270
+ dir = uleb128(&p);
271
+ /* last modified. */
272
+ uleb128(&p);
273
+ /* size of the file. */
274
+ uleb128(&p);
275
+
276
+ if (i == file) {
277
+ line->filename = filename;
278
+ line->dirname = get_nth_dirname(dir, include_directories);
279
+ }
280
+ }
281
+ }
282
+
283
+ static void
284
+ fill_line(int num_traces, void **traces, uintptr_t addr, int file, int line,
285
+ char *include_directories, char *filenames,
286
+ obj_info_t *obj, line_info_t *lines, int offset)
287
+ {
288
+ int i;
289
+ addr += obj->base_addr - obj->vmaddr;
290
+ for (i = offset; i < num_traces; i++) {
291
+ uintptr_t a = (uintptr_t)traces[i];
292
+ /* We assume one line code doesn't result >100 bytes of native code.
293
+ We may want more reliable way eventually... */
294
+ if (addr < a && a < addr + 100) {
295
+ fill_filename(file, include_directories, filenames, &lines[i], obj);
296
+ lines[i].line = line;
297
+ }
298
+ }
299
+ }
300
+
301
+ struct LineNumberProgramHeader {
302
+ uint64_t unit_length;
303
+ uint16_t version;
304
+ uint8_t format; /* 4 or 8 */
305
+ uint64_t header_length;
306
+ uint8_t minimum_instruction_length;
307
+ uint8_t maximum_operations_per_instruction;
308
+ uint8_t default_is_stmt;
309
+ int8_t line_base;
310
+ uint8_t line_range;
311
+ uint8_t opcode_base;
312
+ /* uint8_t standard_opcode_lengths[opcode_base-1]; */
313
+ const char *include_directories;
314
+ const char *filenames;
315
+ const char *cu_start;
316
+ const char *cu_end;
317
+ };
318
+
319
+ static int
320
+ parse_debug_line_header(const char **pp, struct LineNumberProgramHeader *header)
321
+ {
322
+ const char *p = *pp;
323
+ header->unit_length = *(uint32_t *)p;
324
+ p += sizeof(uint32_t);
325
+
326
+ header->format = 4;
327
+ if (header->unit_length == 0xffffffff) {
328
+ header->unit_length = *(uint64_t *)p;
329
+ p += sizeof(uint64_t);
330
+ header->format = 8;
331
+ }
332
+
333
+ header->cu_end = p + header->unit_length;
334
+
335
+ header->version = *(uint16_t *)p;
336
+ p += sizeof(uint16_t);
337
+ if (header->version > 4) return -1;
338
+
339
+ header->header_length = header->format == 4 ? *(uint32_t *)p : *(uint64_t *)p;
340
+ p += header->format;
341
+ header->cu_start = p + header->header_length;
342
+
343
+ header->minimum_instruction_length = *(uint8_t *)p++;
344
+
345
+ if (header->version >= 4) {
346
+ /* maximum_operations_per_instruction = *(uint8_t *)p; */
347
+ if (*p != 1) return -1; /* For non-VLIW architectures, this field is 1 */
348
+ p++;
349
+ }
350
+
351
+ header->default_is_stmt = *(uint8_t *)p++;
352
+ header->line_base = *(int8_t *)p++;
353
+ header->line_range = *(uint8_t *)p++;
354
+ header->opcode_base = *(uint8_t *)p++;
355
+ /* header->standard_opcode_lengths = (uint8_t *)p - 1; */
356
+ p += header->opcode_base - 1;
357
+
358
+ header->include_directories = p;
359
+
360
+ /* temporary measure for compress-debug-sections */
361
+ if (p >= header->cu_end) return -1;
362
+
363
+ /* skip include directories */
364
+ while (*p) {
365
+ p = memchr(p, '\0', header->cu_end - p);
366
+ if (!p) return -1;
367
+ p++;
368
+ }
369
+ p++;
370
+
371
+ header->filenames = p;
372
+
373
+ *pp = header->cu_start;
374
+
375
+ return 0;
376
+ }
377
+
378
+ static int
379
+ parse_debug_line_cu(int num_traces, void **traces, char **debug_line,
380
+ obj_info_t *obj, line_info_t *lines, int offset)
381
+ {
382
+ const char *p = (const char *)*debug_line;
383
+ struct LineNumberProgramHeader header;
384
+
385
+ /* The registers. */
386
+ unsigned long addr = 0;
387
+ unsigned int file = 1;
388
+ unsigned int line = 1;
389
+ /* unsigned int column = 0; */
390
+ int is_stmt;
391
+ /* int basic_block = 0; */
392
+ /* int end_sequence = 0; */
393
+ /* int prologue_end = 0; */
394
+ /* int epilogue_begin = 0; */
395
+ /* unsigned int isa = 0; */
396
+
397
+ if (parse_debug_line_header(&p, &header))
398
+ return -1;
399
+ is_stmt = header.default_is_stmt;
400
+
401
+ #define FILL_LINE() \
402
+ do { \
403
+ fill_line(num_traces, traces, addr, file, line, \
404
+ (char *)header.include_directories, \
405
+ (char *)header.filenames, \
406
+ obj, lines, offset); \
407
+ /*basic_block = prologue_end = epilogue_begin = 0;*/ \
408
+ } while (0)
409
+
410
+ while (p < header.cu_end) {
411
+ unsigned long a;
412
+ unsigned char op = *p++;
413
+ switch (op) {
414
+ case DW_LNS_copy:
415
+ FILL_LINE();
416
+ break;
417
+ case DW_LNS_advance_pc:
418
+ a = uleb128((char **)&p);
419
+ addr += a;
420
+ break;
421
+ case DW_LNS_advance_line: {
422
+ long a = sleb128((char **)&p);
423
+ line += a;
424
+ break;
425
+ }
426
+ case DW_LNS_set_file:
427
+ file = (unsigned int)uleb128((char **)&p);
428
+ break;
429
+ case DW_LNS_set_column:
430
+ /*column = (unsigned int)*/(void)uleb128((char **)&p);
431
+ break;
432
+ case DW_LNS_negate_stmt:
433
+ is_stmt = !is_stmt;
434
+ break;
435
+ case DW_LNS_set_basic_block:
436
+ /*basic_block = 1; */
437
+ break;
438
+ case DW_LNS_const_add_pc:
439
+ a = ((255UL - header.opcode_base) / header.line_range) *
440
+ header.minimum_instruction_length;
441
+ addr += a;
442
+ break;
443
+ case DW_LNS_fixed_advance_pc:
444
+ a = *(unsigned char *)p++;
445
+ addr += a;
446
+ break;
447
+ case DW_LNS_set_prologue_end:
448
+ /* prologue_end = 1; */
449
+ break;
450
+ case DW_LNS_set_epilogue_begin:
451
+ /* epilogue_begin = 1; */
452
+ break;
453
+ case DW_LNS_set_isa:
454
+ /* isa = (unsigned int)*/(void)uleb128((char **)&p);
455
+ break;
456
+ case 0:
457
+ a = *(unsigned char *)p++;
458
+ op = *p++;
459
+ switch (op) {
460
+ case DW_LNE_end_sequence:
461
+ /* end_sequence = 1; */
462
+ FILL_LINE();
463
+ addr = 0;
464
+ file = 1;
465
+ line = 1;
466
+ /* column = 0; */
467
+ is_stmt = header.default_is_stmt;
468
+ /* end_sequence = 0; */
469
+ /* isa = 0; */
470
+ break;
471
+ case DW_LNE_set_address:
472
+ addr = *(unsigned long *)p;
473
+ p += sizeof(unsigned long);
474
+ break;
475
+ case DW_LNE_define_file:
476
+ kprintf("Unsupported operation in %s\n",
477
+ binary_filename);
478
+ break;
479
+ case DW_LNE_set_discriminator:
480
+ /* TODO:currently ignore */
481
+ uleb128((char **)&p);
482
+ break;
483
+ default:
484
+ kprintf("Unknown extended opcode: %d in %s\n",
485
+ op, binary_filename);
486
+ }
487
+ break;
488
+ default: {
489
+ uint8_t adjusted_opcode = op - header.opcode_base;
490
+ uint8_t operation_advance = adjusted_opcode / header.line_range;
491
+ /* NOTE: this code doesn't support VLIW */
492
+ addr += operation_advance * header.minimum_instruction_length;
493
+ line += header.line_base + (adjusted_opcode % header.line_range);
494
+ FILL_LINE();
495
+ }
496
+ }
497
+ }
498
+ *debug_line = (char *)p;
499
+ return 0;
500
+ }
501
+
502
+ static int
503
+ parse_debug_line(int num_traces, void **traces,
504
+ char *debug_line, unsigned long size,
505
+ obj_info_t *obj, line_info_t *lines, int offset)
506
+ {
507
+ char *debug_line_end = debug_line + size;
508
+ while (debug_line < debug_line_end) {
509
+ if (parse_debug_line_cu(num_traces, traces, &debug_line, obj, lines, offset))
510
+ return -1;
511
+ }
512
+ if (debug_line != debug_line_end) {
513
+ kprintf("Unexpected size of .debug_line in %s\n",
514
+ binary_filename);
515
+ }
516
+ return 0;
517
+ }
518
+
519
+ /* read file and fill lines */
520
+ static uintptr_t
521
+ fill_lines(int num_traces, void **traces, int check_debuglink,
522
+ obj_info_t **objp, line_info_t *lines, int offset);
523
+
524
+ static void
525
+ append_obj(obj_info_t **objp)
526
+ {
527
+ obj_info_t *newobj = calloc(1, sizeof(obj_info_t));
528
+ if (*objp) (*objp)->next = newobj;
529
+ *objp = newobj;
530
+ }
531
+
532
+ #ifdef USE_ELF
533
+ static void
534
+ follow_debuglink(const char *debuglink, int num_traces, void **traces,
535
+ obj_info_t **objp, line_info_t *lines, int offset)
536
+ {
537
+ /* Ideally we should check 4 paths to follow gnu_debuglink,
538
+ but we handle only one case for now as this format is used
539
+ by some linux distributions. See GDB's info for detail. */
540
+ static const char global_debug_dir[] = "/usr/lib/debug";
541
+ const size_t global_debug_dir_len = sizeof(global_debug_dir) - 1;
542
+ char *p;
543
+ obj_info_t *o1 = *objp, *o2;
544
+ size_t len;
545
+
546
+ p = strrchr(binary_filename, '/');
547
+ if (!p) {
548
+ return;
549
+ }
550
+ p[1] = '\0';
551
+
552
+ len = strlen(binary_filename);
553
+ if (len >= PATH_MAX - global_debug_dir_len)
554
+ len = PATH_MAX - global_debug_dir_len - 1;
555
+ memmove(binary_filename + global_debug_dir_len, binary_filename, len);
556
+ memcpy(binary_filename, global_debug_dir, global_debug_dir_len);
557
+ len += global_debug_dir_len;
558
+ strlcpy(binary_filename + len, debuglink, PATH_MAX - len);
559
+
560
+ append_obj(objp);
561
+ o2 = *objp;
562
+ o2->base_addr = o1->base_addr;
563
+ o2->path = o1->path;
564
+ fill_lines(num_traces, traces, 0, objp, lines, offset);
565
+ }
566
+ #endif
567
+
568
+ enum
569
+ {
570
+ DW_TAG_compile_unit = 0x11,
571
+ DW_TAG_inlined_subroutine = 0x1d,
572
+ DW_TAG_subprogram = 0x2e,
573
+ };
574
+
575
+ /* Attributes encodings */
576
+ enum
577
+ {
578
+ DW_AT_sibling = 0x01,
579
+ DW_AT_location = 0x02,
580
+ DW_AT_name = 0x03,
581
+ /* Reserved 0x04 */
582
+ /* Reserved 0x05 */
583
+ /* Reserved 0x06 */
584
+ /* Reserved 0x07 */
585
+ /* Reserved 0x08 */
586
+ DW_AT_ordering = 0x09,
587
+ /* Reserved 0x0a */
588
+ DW_AT_byte_size = 0x0b,
589
+ /* Reserved 0x0c */
590
+ DW_AT_bit_size = 0x0d,
591
+ /* Reserved 0x0e */
592
+ /* Reserved 0x0f */
593
+ DW_AT_stmt_list = 0x10,
594
+ DW_AT_low_pc = 0x11,
595
+ DW_AT_high_pc = 0x12,
596
+ DW_AT_language = 0x13,
597
+ /* Reserved 0x14 */
598
+ DW_AT_discr = 0x15,
599
+ DW_AT_discr_value = 0x16,
600
+ DW_AT_visibility = 0x17,
601
+ DW_AT_import = 0x18,
602
+ DW_AT_string_length = 0x19,
603
+ DW_AT_common_reference = 0x1a,
604
+ DW_AT_comp_dir = 0x1b,
605
+ DW_AT_const_value = 0x1c,
606
+ DW_AT_containing_type = 0x1d,
607
+ DW_AT_default_value = 0x1e,
608
+ /* Reserved 0x1f */
609
+ DW_AT_inline = 0x20,
610
+ DW_AT_is_optional = 0x21,
611
+ DW_AT_lower_bound = 0x22,
612
+ /* Reserved 0x23 */
613
+ /* Reserved 0x24 */
614
+ DW_AT_producer = 0x25,
615
+ /* Reserved 0x26 */
616
+ DW_AT_prototyped = 0x27,
617
+ /* Reserved 0x28 */
618
+ /* Reserved 0x29 */
619
+ DW_AT_return_addr = 0x2a,
620
+ /* Reserved 0x2b */
621
+ DW_AT_start_scope = 0x2c,
622
+ /* Reserved 0x2d */
623
+ DW_AT_bit_stride = 0x2e,
624
+ DW_AT_upper_bound = 0x2f,
625
+ /* Reserved 0x30 */
626
+ DW_AT_abstract_origin = 0x31,
627
+ DW_AT_accessibility = 0x32,
628
+ DW_AT_address_class = 0x33,
629
+ DW_AT_artificial = 0x34,
630
+ DW_AT_base_types = 0x35,
631
+ DW_AT_calling_convention = 0x36,
632
+ DW_AT_count = 0x37,
633
+ DW_AT_data_member_location = 0x38,
634
+ DW_AT_decl_column = 0x39,
635
+ DW_AT_decl_file = 0x3a,
636
+ DW_AT_decl_line = 0x3b,
637
+ DW_AT_declaration = 0x3c,
638
+ DW_AT_discr_list = 0x3d,
639
+ DW_AT_encoding = 0x3e,
640
+ DW_AT_external = 0x3f,
641
+ DW_AT_frame_base = 0x40,
642
+ DW_AT_friend = 0x41,
643
+ DW_AT_identifier_case = 0x42,
644
+ /* Reserved 0x43 */
645
+ DW_AT_namelist_item = 0x44,
646
+ DW_AT_priority = 0x45,
647
+ DW_AT_segment = 0x46,
648
+ DW_AT_specification = 0x47,
649
+ DW_AT_static_link = 0x48,
650
+ DW_AT_type = 0x49,
651
+ DW_AT_use_location = 0x4a,
652
+ DW_AT_variable_parameter = 0x4b,
653
+ DW_AT_virtuality = 0x4c,
654
+ DW_AT_vtable_elem_location = 0x4d,
655
+ DW_AT_allocated = 0x4e,
656
+ DW_AT_associated = 0x4f,
657
+ DW_AT_data_location = 0x50,
658
+ DW_AT_byte_stride = 0x51,
659
+ DW_AT_entry_pc = 0x52,
660
+ DW_AT_use_UTF8 = 0x53,
661
+ DW_AT_extension = 0x54,
662
+ DW_AT_ranges = 0x55,
663
+ DW_AT_trampoline = 0x56,
664
+ DW_AT_call_column = 0x57,
665
+ DW_AT_call_file = 0x58,
666
+ DW_AT_call_line = 0x59,
667
+ DW_AT_description = 0x5a,
668
+ DW_AT_binary_scale = 0x5b,
669
+ DW_AT_decimal_scale = 0x5c,
670
+ DW_AT_small = 0x5d,
671
+ DW_AT_decimal_sign = 0x5e,
672
+ DW_AT_digit_count = 0x5f,
673
+ DW_AT_picture_string = 0x60,
674
+ DW_AT_mutable = 0x61,
675
+ DW_AT_threads_scaled = 0x62,
676
+ DW_AT_explicit = 0x63,
677
+ DW_AT_object_pointer = 0x64,
678
+ DW_AT_endianity = 0x65,
679
+ DW_AT_elemental = 0x66,
680
+ DW_AT_pure = 0x67,
681
+ DW_AT_recursive = 0x68,
682
+ DW_AT_signature = 0x69,
683
+ DW_AT_main_subprogram = 0x6a,
684
+ DW_AT_data_bit_offset = 0x6b,
685
+ DW_AT_const_expr = 0x6c,
686
+ DW_AT_enum_class = 0x6d,
687
+ DW_AT_linkage_name = 0x6e,
688
+ DW_AT_string_length_bit_size = 0x6f,
689
+ DW_AT_string_length_byte_size = 0x70,
690
+ DW_AT_rank = 0x71,
691
+ DW_AT_str_offsets_base = 0x72,
692
+ DW_AT_addr_base = 0x73,
693
+ DW_AT_rnglists_base = 0x74,
694
+ /* Reserved 0x75 */
695
+ DW_AT_dwo_name = 0x76,
696
+ DW_AT_reference = 0x77,
697
+ DW_AT_rvalue_reference = 0x78,
698
+ DW_AT_macros = 0x79,
699
+ DW_AT_call_all_calls = 0x7a,
700
+ DW_AT_call_all_source_calls = 0x7b,
701
+ DW_AT_call_all_tail_calls = 0x7c,
702
+ DW_AT_call_return_pc = 0x7d,
703
+ DW_AT_call_value = 0x7e,
704
+ DW_AT_call_origin = 0x7f,
705
+ DW_AT_call_parameter = 0x80,
706
+ DW_AT_call_pc = 0x81,
707
+ DW_AT_call_tail_call = 0x82,
708
+ DW_AT_call_target = 0x83,
709
+ DW_AT_call_target_clobbered = 0x84,
710
+ DW_AT_call_data_location = 0x85,
711
+ DW_AT_call_data_value = 0x86,
712
+ DW_AT_noreturn = 0x87,
713
+ DW_AT_alignment = 0x88,
714
+ DW_AT_export_symbols = 0x89,
715
+ DW_AT_deleted = 0x8a,
716
+ DW_AT_defaulted = 0x8b,
717
+ DW_AT_loclists_base = 0x8c,
718
+ DW_AT_lo_user = 0x2000,
719
+ DW_AT_hi_user = 0x3fff
720
+ };
721
+
722
+ /* Attribute form encodings */
723
+ enum
724
+ {
725
+ DW_FORM_addr = 0x01,
726
+ /* Reserved 0x02 */
727
+ DW_FORM_block2 = 0x03,
728
+ DW_FORM_block4 = 0x04,
729
+ DW_FORM_data2 = 0x05,
730
+ DW_FORM_data4 = 0x06,
731
+ DW_FORM_data8 = 0x07,
732
+ DW_FORM_string = 0x08,
733
+ DW_FORM_block = 0x09,
734
+ DW_FORM_block1 = 0x0a,
735
+ DW_FORM_data1 = 0x0b,
736
+ DW_FORM_flag = 0x0c,
737
+ DW_FORM_sdata = 0x0d,
738
+ DW_FORM_strp = 0x0e,
739
+ DW_FORM_udata = 0x0f,
740
+ DW_FORM_ref_addr = 0x10,
741
+ DW_FORM_ref1 = 0x11,
742
+ DW_FORM_ref2 = 0x12,
743
+ DW_FORM_ref4 = 0x13,
744
+ DW_FORM_ref8 = 0x14,
745
+ DW_FORM_ref_udata = 0x15,
746
+ DW_FORM_indirect = 0x16,
747
+ DW_FORM_sec_offset = 0x17,
748
+ DW_FORM_exprloc = 0x18,
749
+ DW_FORM_flag_present = 0x19,
750
+ DW_FORM_strx = 0x1a,
751
+ DW_FORM_addrx = 0x1b,
752
+ DW_FORM_ref_sup4 = 0x1c,
753
+ DW_FORM_strp_sup = 0x1d,
754
+ DW_FORM_data16 = 0x1e,
755
+ DW_FORM_line_strp = 0x1f,
756
+ DW_FORM_ref_sig8 = 0x20,
757
+ DW_FORM_implicit_const = 0x21,
758
+ DW_FORM_loclistx = 0x22,
759
+ DW_FORM_rnglistx = 0x23,
760
+ DW_FORM_ref_sup8 = 0x24,
761
+ DW_FORM_strx1 = 0x25,
762
+ DW_FORM_strx2 = 0x26,
763
+ DW_FORM_strx3 = 0x27,
764
+ DW_FORM_strx4 = 0x28,
765
+ DW_FORM_addrx1 = 0x29,
766
+ DW_FORM_addrx2 = 0x2a,
767
+ DW_FORM_addrx3 = 0x2b,
768
+ DW_FORM_addrx4 = 0x2c
769
+ };
770
+
771
+ enum {
772
+ VAL_none = 0,
773
+ VAL_cstr = 1,
774
+ VAL_data = 2,
775
+ VAL_uint = 3,
776
+ VAL_int = 4
777
+ };
778
+
779
+ # define ABBREV_TABLE_SIZE 256
780
+ typedef struct {
781
+ obj_info_t *obj;
782
+ char *file;
783
+ char *current_cu;
784
+ uint64_t current_low_pc;
785
+ char *debug_line_cu_end;
786
+ char *debug_line_files;
787
+ char *debug_line_directories;
788
+ char *p;
789
+ char *cu_end;
790
+ char *pend;
791
+ char *q0;
792
+ char *q;
793
+ int format; // 4 or 8
794
+ uint8_t address_size;
795
+ int level;
796
+ char *abbrev_table[ABBREV_TABLE_SIZE];
797
+ } DebugInfoReader;
798
+
799
+ typedef struct {
800
+ ptrdiff_t pos;
801
+ int tag;
802
+ int has_children;
803
+ } DIE;
804
+
805
+ typedef struct {
806
+ union {
807
+ char *ptr;
808
+ uint64_t uint64;
809
+ int64_t int64;
810
+ } as;
811
+ uint64_t off;
812
+ uint64_t at;
813
+ uint64_t form;
814
+ size_t size;
815
+ int type;
816
+ } DebugInfoValue;
817
+
818
+ /* TODO: Big Endian */
819
+ #define MERGE_2INTS(a,b,sz) (((uint64_t)(b)<<sz)|(a))
820
+
821
+ static uint16_t
822
+ get_uint16(const uint8_t *p)
823
+ {
824
+ return (uint16_t)MERGE_2INTS(p[0],p[1],8);
825
+ }
826
+
827
+ static uint32_t
828
+ get_uint32(const uint8_t *p)
829
+ {
830
+ return (uint32_t)MERGE_2INTS(get_uint16(p),get_uint16(p+2),16);
831
+ }
832
+
833
+ static uint64_t
834
+ get_uint64(const uint8_t *p)
835
+ {
836
+ return MERGE_2INTS(get_uint32(p),get_uint32(p+4),32);
837
+ }
838
+
839
+ static uint8_t
840
+ read_uint8(char **ptr)
841
+ {
842
+ const unsigned char *p = (const unsigned char *)*ptr;
843
+ *ptr = (char *)(p + 1);
844
+ return *p;
845
+ }
846
+
847
+ static uint16_t
848
+ read_uint16(char **ptr)
849
+ {
850
+ const unsigned char *p = (const unsigned char *)*ptr;
851
+ *ptr = (char *)(p + 2);
852
+ return get_uint16(p);
853
+ }
854
+
855
+ static uint32_t
856
+ read_uint24(char **ptr)
857
+ {
858
+ const unsigned char *p = (const unsigned char *)*ptr;
859
+ *ptr = (char *)(p + 3);
860
+ return (*p << 16) | get_uint16(p+1);
861
+ }
862
+
863
+ static uint32_t
864
+ read_uint32(char **ptr)
865
+ {
866
+ const unsigned char *p = (const unsigned char *)*ptr;
867
+ *ptr = (char *)(p + 4);
868
+ return get_uint32(p);
869
+ }
870
+
871
+ static uint64_t
872
+ read_uint64(char **ptr)
873
+ {
874
+ const unsigned char *p = (const unsigned char *)*ptr;
875
+ *ptr = (char *)(p + 8);
876
+ return get_uint64(p);
877
+ }
878
+
879
+ static uintptr_t
880
+ read_uintptr(char **ptr)
881
+ {
882
+ const unsigned char *p = (const unsigned char *)*ptr;
883
+ *ptr = (char *)(p + SIZEOF_VOIDP);
884
+ #if SIZEOF_VOIDP == 8
885
+ return get_uint64(p);
886
+ #else
887
+ return get_uint32(p);
888
+ #endif
889
+ }
890
+
891
+ static uint64_t
892
+ read_uint(DebugInfoReader *reader)
893
+ {
894
+ if (reader->format == 4) {
895
+ return read_uint32(&reader->p);
896
+ } else { /* 64 bit */
897
+ return read_uint64(&reader->p);
898
+ }
899
+ }
900
+
901
+ static uint64_t
902
+ read_uleb128(DebugInfoReader *reader)
903
+ {
904
+ return uleb128(&reader->p);
905
+ }
906
+
907
+ static int64_t
908
+ read_sleb128(DebugInfoReader *reader)
909
+ {
910
+ return sleb128(&reader->p);
911
+ }
912
+
913
+ static void
914
+ debug_info_reader_init(DebugInfoReader *reader, obj_info_t *obj)
915
+ {
916
+ reader->file = obj->mapped;
917
+ reader->obj = obj;
918
+ reader->p = obj->debug_info.ptr;
919
+ reader->pend = obj->debug_info.ptr + obj->debug_info.size;
920
+ reader->debug_line_cu_end = obj->debug_line.ptr;
921
+ }
922
+
923
+ static void
924
+ di_read_debug_abbrev_cu(DebugInfoReader *reader)
925
+ {
926
+ uint64_t prev = 0;
927
+ char *p = reader->q0;
928
+ for (;;) {
929
+ uint64_t abbrev_number = uleb128(&p);
930
+ if (abbrev_number <= prev) break;
931
+ if (abbrev_number < ABBREV_TABLE_SIZE) {
932
+ reader->abbrev_table[abbrev_number] = p;
933
+ }
934
+ prev = abbrev_number;
935
+ uleb128(&p); /* tag */
936
+ p++; /* has_children */
937
+ /* skip content */
938
+ for (;;) {
939
+ uint64_t at = uleb128(&p);
940
+ uint64_t form = uleb128(&p);
941
+ if (!at && !form) break;
942
+ }
943
+ }
944
+ }
945
+
946
+ static int
947
+ di_read_debug_line_cu(DebugInfoReader *reader)
948
+ {
949
+ const char *p;
950
+ struct LineNumberProgramHeader header;
951
+
952
+ p = (const char *)reader->debug_line_cu_end;
953
+ if (parse_debug_line_header(&p, &header))
954
+ return -1;
955
+
956
+ reader->debug_line_cu_end = (char *)header.cu_end;
957
+ reader->debug_line_directories = (char *)header.include_directories;
958
+ reader->debug_line_files = (char *)header.filenames;
959
+
960
+ return 0;
961
+ }
962
+
963
+ static void
964
+ set_uint_value(DebugInfoValue *v, uint64_t n)
965
+ {
966
+ v->as.uint64 = n;
967
+ v->type = VAL_uint;
968
+ }
969
+
970
+ static void
971
+ set_int_value(DebugInfoValue *v, int64_t n)
972
+ {
973
+ v->as.int64 = n;
974
+ v->type = VAL_int;
975
+ }
976
+
977
+ static void
978
+ set_cstr_value(DebugInfoValue *v, char *s)
979
+ {
980
+ v->as.ptr = s;
981
+ v->off = 0;
982
+ v->type = VAL_cstr;
983
+ }
984
+
985
+ static void
986
+ set_cstrp_value(DebugInfoValue *v, char *s, uint64_t off)
987
+ {
988
+ v->as.ptr = s;
989
+ v->off = off;
990
+ v->type = VAL_cstr;
991
+ }
992
+
993
+ static void
994
+ set_data_value(DebugInfoValue *v, char *s)
995
+ {
996
+ v->as.ptr = s;
997
+ v->type = VAL_data;
998
+ }
999
+
1000
+ static const char *
1001
+ get_cstr_value(DebugInfoValue *v)
1002
+ {
1003
+ if (v->as.ptr) {
1004
+ return v->as.ptr + v->off;
1005
+ } else {
1006
+ return NULL;
1007
+ }
1008
+ }
1009
+
1010
+ static void
1011
+ debug_info_reader_read_value(DebugInfoReader *reader, uint64_t form, DebugInfoValue *v)
1012
+ {
1013
+ switch (form) {
1014
+ case DW_FORM_addr:
1015
+ if (reader->address_size == 4) {
1016
+ set_uint_value(v, read_uint32(&reader->p));
1017
+ } else if (reader->address_size == 8) {
1018
+ set_uint_value(v, read_uint64(&reader->p));
1019
+ } else {
1020
+ fprintf(stderr,"unknown address_size:%d", reader->address_size);
1021
+ abort();
1022
+ }
1023
+ break;
1024
+ case DW_FORM_block2:
1025
+ v->size = read_uint16(&reader->p);
1026
+ set_data_value(v, reader->p);
1027
+ reader->p += v->size;
1028
+ break;
1029
+ case DW_FORM_block4:
1030
+ v->size = read_uint32(&reader->p);
1031
+ set_data_value(v, reader->p);
1032
+ reader->p += v->size;
1033
+ break;
1034
+ case DW_FORM_data2:
1035
+ set_uint_value(v, read_uint16(&reader->p));
1036
+ break;
1037
+ case DW_FORM_data4:
1038
+ set_uint_value(v, read_uint32(&reader->p));
1039
+ break;
1040
+ case DW_FORM_data8:
1041
+ set_uint_value(v, read_uint64(&reader->p));
1042
+ break;
1043
+ case DW_FORM_string:
1044
+ v->size = strlen(reader->p);
1045
+ set_cstr_value(v, reader->p);
1046
+ reader->p += v->size + 1;
1047
+ break;
1048
+ case DW_FORM_block:
1049
+ v->size = uleb128(&reader->p);
1050
+ set_data_value(v, reader->p);
1051
+ reader->p += v->size;
1052
+ break;
1053
+ case DW_FORM_block1:
1054
+ v->size = read_uint8(&reader->p);
1055
+ set_data_value(v, reader->p);
1056
+ reader->p += v->size;
1057
+ break;
1058
+ case DW_FORM_data1:
1059
+ set_uint_value(v, read_uint8(&reader->p));
1060
+ break;
1061
+ case DW_FORM_flag:
1062
+ set_uint_value(v, read_uint8(&reader->p));
1063
+ break;
1064
+ case DW_FORM_sdata:
1065
+ set_int_value(v, read_sleb128(reader));
1066
+ break;
1067
+ case DW_FORM_strp:
1068
+ set_cstrp_value(v, reader->obj->debug_str.ptr, read_uint(reader));
1069
+ break;
1070
+ case DW_FORM_udata:
1071
+ set_uint_value(v, read_uleb128(reader));
1072
+ break;
1073
+ case DW_FORM_ref_addr:
1074
+ if (reader->address_size == 4) {
1075
+ set_uint_value(v, read_uint32(&reader->p));
1076
+ } else if (reader->address_size == 8) {
1077
+ set_uint_value(v, read_uint64(&reader->p));
1078
+ } else {
1079
+ fprintf(stderr,"unknown address_size:%d", reader->address_size);
1080
+ abort();
1081
+ }
1082
+ break;
1083
+ case DW_FORM_ref1:
1084
+ set_uint_value(v, read_uint8(&reader->p));
1085
+ break;
1086
+ case DW_FORM_ref2:
1087
+ set_uint_value(v, read_uint16(&reader->p));
1088
+ break;
1089
+ case DW_FORM_ref4:
1090
+ set_uint_value(v, read_uint32(&reader->p));
1091
+ break;
1092
+ case DW_FORM_ref8:
1093
+ set_uint_value(v, read_uint64(&reader->p));
1094
+ break;
1095
+ case DW_FORM_ref_udata:
1096
+ set_uint_value(v, uleb128(&reader->p));
1097
+ break;
1098
+ case DW_FORM_indirect:
1099
+ /* TODO: read the referred value */
1100
+ set_uint_value(v, uleb128(&reader->p));
1101
+ break;
1102
+ case DW_FORM_sec_offset:
1103
+ set_uint_value(v, read_uint(reader)); /* offset */
1104
+ /* addrptr: debug_addr */
1105
+ /* lineptr: debug_line */
1106
+ /* loclist: debug_loclists */
1107
+ /* loclistptr: debug_loclists */
1108
+ /* macptr: debug_macro */
1109
+ /* rnglist: debug_rnglists */
1110
+ /* rnglistptr: debug_rnglists */
1111
+ /* stroffsetsptr: debug_str_offsets */
1112
+ break;
1113
+ case DW_FORM_exprloc:
1114
+ v->size = (size_t)read_uleb128(reader);
1115
+ set_data_value(v, reader->p);
1116
+ reader->p += v->size;
1117
+ break;
1118
+ case DW_FORM_flag_present:
1119
+ set_uint_value(v, 1);
1120
+ break;
1121
+ case DW_FORM_strx:
1122
+ set_uint_value(v, uleb128(&reader->p));
1123
+ break;
1124
+ case DW_FORM_addrx:
1125
+ /* TODO: read .debug_addr */
1126
+ set_uint_value(v, uleb128(&reader->p));
1127
+ break;
1128
+ case DW_FORM_ref_sup4:
1129
+ set_uint_value(v, read_uint32(&reader->p));
1130
+ break;
1131
+ case DW_FORM_strp_sup:
1132
+ set_uint_value(v, read_uint(reader));
1133
+ /* *p = reader->sup_file + reader->sup_str->sh_offset + ret; */
1134
+ break;
1135
+ case DW_FORM_data16:
1136
+ v->size = 16;
1137
+ set_data_value(v, reader->p);
1138
+ reader->p += v->size;
1139
+ break;
1140
+ case DW_FORM_line_strp:
1141
+ set_uint_value(v, read_uint(reader));
1142
+ /* *p = reader->file + reader->line->sh_offset + ret; */
1143
+ break;
1144
+ case DW_FORM_ref_sig8:
1145
+ set_uint_value(v, read_uint64(&reader->p));
1146
+ break;
1147
+ case DW_FORM_implicit_const:
1148
+ set_int_value(v, sleb128(&reader->q));
1149
+ break;
1150
+ case DW_FORM_loclistx:
1151
+ set_uint_value(v, read_uleb128(reader));
1152
+ break;
1153
+ case DW_FORM_rnglistx:
1154
+ set_uint_value(v, read_uleb128(reader));
1155
+ break;
1156
+ case DW_FORM_ref_sup8:
1157
+ set_uint_value(v, read_uint64(&reader->p));
1158
+ break;
1159
+ case DW_FORM_strx1:
1160
+ set_uint_value(v, read_uint8(&reader->p));
1161
+ break;
1162
+ case DW_FORM_strx2:
1163
+ set_uint_value(v, read_uint16(&reader->p));
1164
+ break;
1165
+ case DW_FORM_strx3:
1166
+ set_uint_value(v, read_uint24(&reader->p));
1167
+ break;
1168
+ case DW_FORM_strx4:
1169
+ set_uint_value(v, read_uint32(&reader->p));
1170
+ break;
1171
+ case DW_FORM_addrx1:
1172
+ set_uint_value(v, read_uint8(&reader->p));
1173
+ break;
1174
+ case DW_FORM_addrx2:
1175
+ set_uint_value(v, read_uint16(&reader->p));
1176
+ break;
1177
+ case DW_FORM_addrx3:
1178
+ set_uint_value(v, read_uint24(&reader->p));
1179
+ break;
1180
+ case DW_FORM_addrx4:
1181
+ set_uint_value(v, read_uint32(&reader->p));
1182
+ break;
1183
+ case 0:
1184
+ goto fail;
1185
+ break;
1186
+ }
1187
+ return;
1188
+
1189
+ fail:
1190
+ fprintf(stderr, "%d: unsupported form: %#"PRIx64"\n", __LINE__, form);
1191
+ exit(1);
1192
+ }
1193
+
1194
+ /* find abbrev in current compilation unit */
1195
+ static char *
1196
+ di_find_abbrev(DebugInfoReader *reader, uint64_t abbrev_number)
1197
+ {
1198
+ char *p;
1199
+ if (abbrev_number < ABBREV_TABLE_SIZE) {
1200
+ return reader->abbrev_table[abbrev_number];
1201
+ }
1202
+ p = reader->abbrev_table[ABBREV_TABLE_SIZE-1];
1203
+ /* skip 255th record */
1204
+ uleb128(&p); /* tag */
1205
+ p++; /* has_children */
1206
+ /* skip content */
1207
+ for (;;) {
1208
+ uint64_t at = uleb128(&p);
1209
+ uint64_t form = uleb128(&p);
1210
+ if (!at && !form) break;
1211
+ }
1212
+ for (uint64_t n = uleb128(&p); abbrev_number != n; n = uleb128(&p)) {
1213
+ if (n == 0) {
1214
+ fprintf(stderr,"%d: Abbrev Number %"PRId64" not found\n",__LINE__, abbrev_number);
1215
+ exit(1);
1216
+ }
1217
+ uleb128(&p); /* tag */
1218
+ p++; /* has_children */
1219
+ /* skip content */
1220
+ for (;;) {
1221
+ uint64_t at = uleb128(&p);
1222
+ uint64_t form = uleb128(&p);
1223
+ if (!at && !form) break;
1224
+ }
1225
+ }
1226
+ return p;
1227
+ }
1228
+
1229
+ #if 0
1230
+ static void
1231
+ hexdump0(const unsigned char *p, size_t n)
1232
+ {
1233
+ size_t i;
1234
+ fprintf(stderr, " 0 1 2 3 4 5 6 7 8 9 A B C D E F\n");
1235
+ for (i=0; i < n; i++){
1236
+ switch (i & 15) {
1237
+ case 0:
1238
+ fprintf(stderr, "%02zd: %02X ", i/16, p[i]);
1239
+ break;
1240
+ case 15:
1241
+ fprintf(stderr, "%02X\n", p[i]);
1242
+ break;
1243
+ default:
1244
+ fprintf(stderr, "%02X ", p[i]);
1245
+ break;
1246
+ }
1247
+ }
1248
+ if ((i & 15) != 15) {
1249
+ fprintf(stderr, "\n");
1250
+ }
1251
+ }
1252
+ #define hexdump(p,n) hexdump0((const unsigned char *)p, n)
1253
+
1254
+ static void
1255
+ div_inspect(DebugInfoValue *v)
1256
+ {
1257
+ switch (v->type) {
1258
+ case VAL_uint:
1259
+ fprintf(stderr,"%d: type:%d size:%zx v:%lx\n",__LINE__,v->type,v->size,v->as.uint64);
1260
+ break;
1261
+ case VAL_int:
1262
+ fprintf(stderr,"%d: type:%d size:%zx v:%ld\n",__LINE__,v->type,v->size,(int64_t)v->as.uint64);
1263
+ break;
1264
+ case VAL_cstr:
1265
+ fprintf(stderr,"%d: type:%d size:%zx v:'%s'\n",__LINE__,v->type,v->size,v->as.ptr);
1266
+ break;
1267
+ case VAL_data:
1268
+ fprintf(stderr,"%d: type:%d size:%zx v:\n",__LINE__,v->type,v->size);
1269
+ hexdump(v->as.ptr, 16);
1270
+ break;
1271
+ }
1272
+ }
1273
+ #endif
1274
+
1275
+ static DIE *
1276
+ di_read_die(DebugInfoReader *reader, DIE *die)
1277
+ {
1278
+ uint64_t abbrev_number = uleb128(&reader->p);
1279
+ if (abbrev_number == 0) {
1280
+ reader->level--;
1281
+ return NULL;
1282
+ }
1283
+
1284
+ reader->q = di_find_abbrev(reader, abbrev_number);
1285
+
1286
+ die->pos = reader->p - reader->obj->debug_info.ptr - 1;
1287
+ die->tag = (int)uleb128(&reader->q); /* tag */
1288
+ die->has_children = *reader->q++; /* has_children */
1289
+ if (die->has_children) {
1290
+ reader->level++;
1291
+ }
1292
+ return die;
1293
+ }
1294
+
1295
+ static DebugInfoValue *
1296
+ di_read_record(DebugInfoReader *reader, DebugInfoValue *vp)
1297
+ {
1298
+ uint64_t at = uleb128(&reader->q);
1299
+ uint64_t form = uleb128(&reader->q);
1300
+ if (!at || !form) return NULL;
1301
+ vp->at = at;
1302
+ vp->form = form;
1303
+ debug_info_reader_read_value(reader, form, vp);
1304
+ return vp;
1305
+ }
1306
+
1307
+ static void
1308
+ di_skip_records(DebugInfoReader *reader)
1309
+ {
1310
+ for (;;) {
1311
+ DebugInfoValue v = {{}};
1312
+ uint64_t at = uleb128(&reader->q);
1313
+ uint64_t form = uleb128(&reader->q);
1314
+ if (!at || !form) return;
1315
+ debug_info_reader_read_value(reader, form, &v);
1316
+ }
1317
+ }
1318
+
1319
+ typedef struct {
1320
+ uint64_t low_pc;
1321
+ uint64_t high_pc;
1322
+ uint64_t ranges;
1323
+ bool low_pc_set;
1324
+ bool high_pc_set;
1325
+ bool ranges_set;
1326
+ } ranges_t;
1327
+
1328
+ static void
1329
+ ranges_set(ranges_t *ptr, DebugInfoValue *v)
1330
+ {
1331
+ switch (v->at) {
1332
+ case DW_AT_low_pc:
1333
+ ptr->low_pc = v->as.uint64;
1334
+ ptr->low_pc_set = true;
1335
+ break;
1336
+ case DW_AT_high_pc:
1337
+ if (v->form == DW_FORM_addr) {
1338
+ ptr->high_pc = v->as.uint64;
1339
+ }
1340
+ else {
1341
+ ptr->high_pc = ptr->low_pc + v->as.uint64;
1342
+ }
1343
+ ptr->high_pc_set = true;
1344
+ break;
1345
+ case DW_AT_ranges:
1346
+ ptr->ranges = v->as.uint64;
1347
+ ptr->ranges_set = true;
1348
+ break;
1349
+ }
1350
+ }
1351
+
1352
+ static uintptr_t
1353
+ ranges_include(DebugInfoReader *reader, ranges_t *ptr, uint64_t addr)
1354
+ {
1355
+ if (ptr->high_pc_set) {
1356
+ if (ptr->ranges_set || !ptr->low_pc_set) {
1357
+ exit(1);
1358
+ }
1359
+ if (ptr->low_pc <= addr && addr <= ptr->high_pc) {
1360
+ return (uintptr_t)ptr->low_pc;
1361
+ }
1362
+ }
1363
+ else if (ptr->ranges_set) {
1364
+ /* TODO: support base address selection entry */
1365
+ char *p = reader->obj->debug_ranges.ptr + ptr->ranges;
1366
+ uint64_t base = ptr->low_pc_set ? ptr->low_pc : reader->current_low_pc;
1367
+ for (;;) {
1368
+ uintptr_t from = read_uintptr(&p);
1369
+ uintptr_t to = read_uintptr(&p);
1370
+ if (!from && !to) break;
1371
+ if (from == UINTPTR_MAX) {
1372
+ /* base address selection entry */
1373
+ base = to;
1374
+ }
1375
+ else if (base + from <= addr && addr < base + to) {
1376
+ return from;
1377
+ }
1378
+ }
1379
+ }
1380
+ else if (ptr->low_pc_set) {
1381
+ if (ptr->low_pc == addr) {
1382
+ return (uintptr_t)ptr->low_pc;
1383
+ }
1384
+ }
1385
+ return false;
1386
+ }
1387
+
1388
+ #if 0
1389
+ static void
1390
+ ranges_inspect(DebugInfoReader *reader, ranges_t *ptr)
1391
+ {
1392
+ if (ptr->high_pc_set) {
1393
+ if (ptr->ranges_set || !ptr->low_pc_set) {
1394
+ fprintf(stderr,"low_pc_set:%d high_pc_set:%d ranges_set:%d\n",ptr->low_pc_set,ptr->high_pc_set,ptr->ranges_set);
1395
+ exit(1);
1396
+ }
1397
+ fprintf(stderr,"low_pc:%"PRIx64" high_pc:%"PRIx64"\n",ptr->low_pc,ptr->high_pc);
1398
+ }
1399
+ else if (ptr->ranges_set) {
1400
+ char *p = reader->obj->debug_ranges.ptr + ptr->ranges;
1401
+ fprintf(stderr,"low_pc:%"PRIx64" ranges:%"PRIx64" %lx ",ptr->low_pc,ptr->ranges, p-reader->obj->mapped);
1402
+ for (;;) {
1403
+ uintptr_t from = read_uintptr(&p);
1404
+ uintptr_t to = read_uintptr(&p);
1405
+ if (!from && !to) break;
1406
+ fprintf(stderr,"%"PRIx64"-%"PRIx64" ",ptr->low_pc+from,ptr->low_pc+to);
1407
+ }
1408
+ fprintf(stderr,"\n");
1409
+ }
1410
+ else if (ptr->low_pc_set) {
1411
+ fprintf(stderr,"low_pc:%"PRIx64"\n",ptr->low_pc);
1412
+ }
1413
+ else {
1414
+ fprintf(stderr,"empty\n");
1415
+ }
1416
+ }
1417
+ #endif
1418
+
1419
+ static int
1420
+ di_read_cu(DebugInfoReader *reader)
1421
+ {
1422
+ uint64_t unit_length;
1423
+ uint16_t version;
1424
+ uint64_t debug_abbrev_offset;
1425
+ reader->format = 4;
1426
+ reader->current_cu = reader->p;
1427
+ unit_length = read_uint32(&reader->p);
1428
+ if (unit_length == 0xffffffff) {
1429
+ unit_length = read_uint64(&reader->p);
1430
+ reader->format = 8;
1431
+ }
1432
+ reader->cu_end = reader->p + unit_length;
1433
+ version = read_uint16(&reader->p);
1434
+ if (version > 5) {
1435
+ return -1;
1436
+ }
1437
+ else if (version == 5) {
1438
+ /* unit_type = */ read_uint8(&reader->p);
1439
+ reader->address_size = read_uint8(&reader->p);
1440
+ debug_abbrev_offset = read_uint(reader);
1441
+ }
1442
+ else {
1443
+ debug_abbrev_offset = read_uint(reader);
1444
+ reader->address_size = read_uint8(&reader->p);
1445
+ }
1446
+ reader->q0 = reader->obj->debug_abbrev.ptr + debug_abbrev_offset;
1447
+
1448
+ reader->level = 0;
1449
+ di_read_debug_abbrev_cu(reader);
1450
+ if (di_read_debug_line_cu(reader)) return -1;
1451
+
1452
+ #if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER_BUILD_DATE)
1453
+ /* Though DWARF specifies "the applicable base address defaults to the base
1454
+ address of the compilation unit", but GCC seems to use zero as default */
1455
+ #else
1456
+ do {
1457
+ DIE die;
1458
+
1459
+ if (!di_read_die(reader, &die)) continue;
1460
+
1461
+ if (die.tag != DW_TAG_compile_unit) {
1462
+ di_skip_records(reader);
1463
+ break;
1464
+ }
1465
+
1466
+ /* enumerate abbrev */
1467
+ for (;;) {
1468
+ DebugInfoValue v = {{}};
1469
+ if (!di_read_record(reader, &v)) break;
1470
+ switch (v.at) {
1471
+ case DW_AT_low_pc:
1472
+ reader->current_low_pc = v.as.uint64;
1473
+ break;
1474
+ }
1475
+ }
1476
+ } while (0);
1477
+ #endif
1478
+ return 0;
1479
+ }
1480
+
1481
+ static void
1482
+ read_abstract_origin(DebugInfoReader *reader, uint64_t abstract_origin, line_info_t *line)
1483
+ {
1484
+ char *p = reader->p;
1485
+ char *q = reader->q;
1486
+ int level = reader->level;
1487
+ DIE die;
1488
+
1489
+ reader->p = reader->current_cu + abstract_origin;
1490
+ if (!di_read_die(reader, &die)) goto finish;
1491
+
1492
+ /* enumerate abbrev */
1493
+ for (;;) {
1494
+ DebugInfoValue v = {{}};
1495
+ if (!di_read_record(reader, &v)) break;
1496
+ switch (v.at) {
1497
+ case DW_AT_name:
1498
+ line->sname = get_cstr_value(&v);
1499
+ break;
1500
+ }
1501
+ }
1502
+
1503
+ finish:
1504
+ reader->p = p;
1505
+ reader->q = q;
1506
+ reader->level = level;
1507
+ }
1508
+
1509
+ static void
1510
+ debug_info_read(DebugInfoReader *reader, int num_traces, void **traces,
1511
+ line_info_t *lines, int offset) {
1512
+ while (reader->p < reader->cu_end) {
1513
+ DIE die;
1514
+ ranges_t ranges = {};
1515
+ line_info_t line = {};
1516
+
1517
+ if (!di_read_die(reader, &die)) continue;
1518
+ /* fprintf(stderr,"%d:%tx: <%d>\n",__LINE__,die.pos,reader->level,die.tag); */
1519
+
1520
+ if (die.tag != DW_TAG_subprogram && die.tag != DW_TAG_inlined_subroutine) {
1521
+ skip_die:
1522
+ di_skip_records(reader);
1523
+ continue;
1524
+ }
1525
+
1526
+ /* enumerate abbrev */
1527
+ for (;;) {
1528
+ DebugInfoValue v = {{}};
1529
+ /* ptrdiff_t pos = reader->p - reader->p0; */
1530
+ if (!di_read_record(reader, &v)) break;
1531
+ /* fprintf(stderr,"\n%d:%tx: AT:%lx FORM:%lx\n",__LINE__,pos,v.at,v.form); */
1532
+ /* div_inspect(&v); */
1533
+ switch (v.at) {
1534
+ case DW_AT_name:
1535
+ line.sname = get_cstr_value(&v);
1536
+ break;
1537
+ case DW_AT_call_file:
1538
+ fill_filename((int)v.as.uint64, reader->debug_line_directories, reader->debug_line_files, &line, reader->obj);
1539
+ break;
1540
+ case DW_AT_call_line:
1541
+ line.line = (int)v.as.uint64;
1542
+ break;
1543
+ case DW_AT_low_pc:
1544
+ case DW_AT_high_pc:
1545
+ case DW_AT_ranges:
1546
+ ranges_set(&ranges, &v);
1547
+ break;
1548
+ case DW_AT_declaration:
1549
+ goto skip_die;
1550
+ case DW_AT_inline:
1551
+ /* 1 or 3 */
1552
+ break; /* goto skip_die; */
1553
+ case DW_AT_abstract_origin:
1554
+ read_abstract_origin(reader, v.as.uint64, &line);
1555
+ break; /* goto skip_die; */
1556
+ }
1557
+ }
1558
+ /* ranges_inspect(reader, &ranges); */
1559
+ /* fprintf(stderr,"%d:%tx: %x ",__LINE__,diepos,die.tag); */
1560
+ for (int i=offset; i < num_traces; i++) {
1561
+ uintptr_t addr = (uintptr_t)traces[i];
1562
+ uintptr_t offset = addr - reader->obj->base_addr + reader->obj->vmaddr;
1563
+ uintptr_t saddr = ranges_include(reader, &ranges, offset);
1564
+ if (saddr) {
1565
+ /* fprintf(stderr, "%d:%tx: %d %lx->%lx %x %s: %s/%s %d %s %s %s\n",__LINE__,die.pos, i,addr,offset, die.tag,line.sname,line.dirname,line.filename,line.line,reader->obj->path,line.sname,lines[i].sname); */
1566
+ if (lines[i].sname) {
1567
+ line_info_t *lp = malloc(sizeof(line_info_t));
1568
+ memcpy(lp, &lines[i], sizeof(line_info_t));
1569
+ lines[i].next = lp;
1570
+ lp->dirname = line.dirname;
1571
+ lp->filename = line.filename;
1572
+ lp->line = line.line;
1573
+ lp->saddr = 0;
1574
+ }
1575
+ lines[i].path = reader->obj->path;
1576
+ lines[i].base_addr = line.base_addr;
1577
+ lines[i].sname = line.sname;
1578
+ lines[i].saddr = saddr + reader->obj->base_addr - reader->obj->vmaddr;
1579
+ }
1580
+ }
1581
+ }
1582
+ }
1583
+
1584
+ #ifdef USE_ELF
1585
+ static unsigned long
1586
+ uncompress_debug_section(ElfW(Shdr) *shdr, char *file, char **ptr)
1587
+ {
1588
+ #ifdef SUPPORT_COMPRESSED_DEBUG_LINE
1589
+ ElfW(Chdr) *chdr = (ElfW(Chdr) *)(file + shdr->sh_offset);
1590
+ unsigned long destsize = chdr->ch_size;
1591
+ int ret = 0;
1592
+
1593
+ if (chdr->ch_type != ELFCOMPRESS_ZLIB) {
1594
+ /* unsupported compression type */
1595
+ return 0;
1596
+ }
1597
+
1598
+ *ptr = malloc(destsize);
1599
+ if (!*ptr) return 0;
1600
+ ret = uncompress((Bytef *)*ptr, &destsize,
1601
+ (const Bytef*)chdr + sizeof(ElfW(Chdr)),
1602
+ shdr->sh_size - sizeof(ElfW(Chdr)));
1603
+ if (ret != Z_OK) goto fail;
1604
+ return destsize;
1605
+
1606
+ fail:
1607
+ free(*ptr);
1608
+ #endif
1609
+ return 0;
1610
+ }
1611
+
1612
+ /* read file and fill lines */
1613
+ static uintptr_t
1614
+ fill_lines(int num_traces, void **traces, int check_debuglink,
1615
+ obj_info_t **objp, line_info_t *lines, int offset)
1616
+ {
1617
+ int i, j;
1618
+ char *shstr;
1619
+ ElfW(Ehdr) *ehdr;
1620
+ ElfW(Shdr) *shdr, *shstr_shdr;
1621
+ ElfW(Shdr) *gnu_debuglink_shdr = NULL;
1622
+ int fd;
1623
+ off_t filesize;
1624
+ char *file;
1625
+ ElfW(Shdr) *symtab_shdr = NULL, *strtab_shdr = NULL;
1626
+ ElfW(Shdr) *dynsym_shdr = NULL, *dynstr_shdr = NULL;
1627
+ obj_info_t *obj = *objp;
1628
+ uintptr_t dladdr_fbase = 0;
1629
+
1630
+ fd = open(binary_filename, O_RDONLY);
1631
+ if (fd < 0) {
1632
+ goto fail;
1633
+ }
1634
+ filesize = lseek(fd, 0, SEEK_END);
1635
+ if (filesize < 0) {
1636
+ int e = errno;
1637
+ close(fd);
1638
+ kprintf("lseek: %s\n", strerror(e));
1639
+ goto fail;
1640
+ }
1641
+ #if SIZEOF_OFF_T > SIZEOF_SIZE_T
1642
+ if (filesize > (off_t)SIZE_MAX) {
1643
+ close(fd);
1644
+ kprintf("Too large file %s\n", binary_filename);
1645
+ goto fail;
1646
+ }
1647
+ #endif
1648
+ lseek(fd, 0, SEEK_SET);
1649
+ /* async-signal unsafe */
1650
+ file = (char *)mmap(NULL, (size_t)filesize, PROT_READ, MAP_SHARED, fd, 0);
1651
+ if (file == MAP_FAILED) {
1652
+ int e = errno;
1653
+ close(fd);
1654
+ kprintf("mmap: %s\n", strerror(e));
1655
+ goto fail;
1656
+ }
1657
+ close(fd);
1658
+
1659
+ ehdr = (ElfW(Ehdr) *)file;
1660
+ if (memcmp(ehdr->e_ident, "\177ELF", 4) != 0) {
1661
+ /*
1662
+ * Huh? Maybe filename was overridden by setproctitle() and
1663
+ * it match non-elf file.
1664
+ */
1665
+ goto fail;
1666
+ }
1667
+ obj->mapped = file;
1668
+ obj->mapped_size = (size_t)filesize;
1669
+
1670
+ shdr = (ElfW(Shdr) *)(file + ehdr->e_shoff);
1671
+
1672
+ shstr_shdr = shdr + ehdr->e_shstrndx;
1673
+ shstr = file + shstr_shdr->sh_offset;
1674
+
1675
+ for (i = 0; i < ehdr->e_shnum; i++) {
1676
+ char *section_name = shstr + shdr[i].sh_name;
1677
+ switch (shdr[i].sh_type) {
1678
+ case SHT_STRTAB:
1679
+ if (!strcmp(section_name, ".strtab")) {
1680
+ strtab_shdr = shdr + i;
1681
+ }
1682
+ else if (!strcmp(section_name, ".dynstr")) {
1683
+ dynstr_shdr = shdr + i;
1684
+ }
1685
+ break;
1686
+ case SHT_SYMTAB:
1687
+ /* if (!strcmp(section_name, ".symtab")) */
1688
+ symtab_shdr = shdr + i;
1689
+ break;
1690
+ case SHT_DYNSYM:
1691
+ /* if (!strcmp(section_name, ".dynsym")) */
1692
+ dynsym_shdr = shdr + i;
1693
+ break;
1694
+ case SHT_PROGBITS:
1695
+ if (!strcmp(section_name, ".gnu_debuglink")) {
1696
+ gnu_debuglink_shdr = shdr + i;
1697
+ }
1698
+ else {
1699
+ const char *debug_section_names[] = {
1700
+ ".debug_abbrev",
1701
+ ".debug_info",
1702
+ ".debug_line",
1703
+ ".debug_ranges",
1704
+ ".debug_str"
1705
+ };
1706
+
1707
+ for (j=0; j < DWARF_SECTION_COUNT; j++) {
1708
+ struct dwarf_section *s = obj_dwarf_section_at(obj, j);
1709
+
1710
+ if (strcmp(section_name, debug_section_names[j]) != 0)
1711
+ continue;
1712
+
1713
+ s->ptr = file + shdr[i].sh_offset;
1714
+ s->size = shdr[i].sh_size;
1715
+ s->flags = shdr[i].sh_flags;
1716
+ if (s->flags & SHF_COMPRESSED) {
1717
+ s->size = uncompress_debug_section(&shdr[i], file, &s->ptr);
1718
+ if (!s->size) goto fail;
1719
+ }
1720
+ break;
1721
+ }
1722
+ }
1723
+ break;
1724
+ }
1725
+ }
1726
+
1727
+ if (offset == -1) {
1728
+ /* main executable */
1729
+ offset = 0;
1730
+ if (dynsym_shdr && dynstr_shdr) {
1731
+ char *strtab = file + dynstr_shdr->sh_offset;
1732
+ ElfW(Sym) *symtab = (ElfW(Sym) *)(file + dynsym_shdr->sh_offset);
1733
+ int symtab_count = (int)(dynsym_shdr->sh_size / sizeof(ElfW(Sym)));
1734
+ void *handle = dlopen(NULL, RTLD_NOW|RTLD_LOCAL);
1735
+ if (handle) {
1736
+ for (j = 0; j < symtab_count; j++) {
1737
+ ElfW(Sym) *sym = &symtab[j];
1738
+ Dl_info info;
1739
+ void *s;
1740
+ if (ELF_ST_TYPE(sym->st_info) != STT_FUNC || sym->st_size == 0) continue;
1741
+ s = dlsym(handle, strtab + sym->st_name);
1742
+ if (s && dladdr(s, &info)) {
1743
+ obj->base_addr = dladdr_fbase;
1744
+ dladdr_fbase = (uintptr_t)info.dli_fbase;
1745
+ break;
1746
+ }
1747
+ }
1748
+ dlclose(handle);
1749
+ }
1750
+ if (ehdr->e_type == ET_EXEC) {
1751
+ obj->base_addr = 0;
1752
+ }
1753
+ else {
1754
+ /* PIE (position-independent executable) */
1755
+ obj->base_addr = dladdr_fbase;
1756
+ }
1757
+ }
1758
+ }
1759
+
1760
+ if (obj->debug_info.ptr && obj->debug_abbrev.ptr) {
1761
+ DebugInfoReader reader;
1762
+ debug_info_reader_init(&reader, obj);
1763
+ i = 0;
1764
+ while (reader.p < reader.pend) {
1765
+ /* fprintf(stderr, "%d:%tx: CU[%d]\n", __LINE__, reader.p - reader.obj->debug_info.ptr, i++); */
1766
+ if (di_read_cu(&reader)) goto use_symtab;
1767
+ debug_info_read(&reader, num_traces, traces, lines, offset);
1768
+ }
1769
+ }
1770
+ else {
1771
+ /* This file doesn't have dwarf, use symtab or dynsym */
1772
+ use_symtab:
1773
+ if (!symtab_shdr) {
1774
+ /* This file doesn't have symtab, use dynsym instead */
1775
+ symtab_shdr = dynsym_shdr;
1776
+ strtab_shdr = dynstr_shdr;
1777
+ }
1778
+
1779
+ if (symtab_shdr && strtab_shdr) {
1780
+ char *strtab = file + strtab_shdr->sh_offset;
1781
+ ElfW(Sym) *symtab = (ElfW(Sym) *)(file + symtab_shdr->sh_offset);
1782
+ int symtab_count = (int)(symtab_shdr->sh_size / sizeof(ElfW(Sym)));
1783
+ for (j = 0; j < symtab_count; j++) {
1784
+ ElfW(Sym) *sym = &symtab[j];
1785
+ uintptr_t saddr = (uintptr_t)sym->st_value + obj->base_addr;
1786
+ if (ELF_ST_TYPE(sym->st_info) != STT_FUNC) continue;
1787
+ for (i = offset; i < num_traces; i++) {
1788
+ uintptr_t d = (uintptr_t)traces[i] - saddr;
1789
+ if (lines[i].line > 0 || d > (uintptr_t)sym->st_size)
1790
+ continue;
1791
+ /* fill symbol name and addr from .symtab */
1792
+ if (!lines[i].sname) lines[i].sname = strtab + sym->st_name;
1793
+ lines[i].saddr = saddr;
1794
+ lines[i].path = obj->path;
1795
+ lines[i].base_addr = obj->base_addr;
1796
+ }
1797
+ }
1798
+ }
1799
+ }
1800
+
1801
+ if (!obj->debug_line.ptr) {
1802
+ /* This file doesn't have .debug_line section,
1803
+ let's check .gnu_debuglink section instead. */
1804
+ if (gnu_debuglink_shdr && check_debuglink) {
1805
+ follow_debuglink(file + gnu_debuglink_shdr->sh_offset,
1806
+ num_traces, traces,
1807
+ objp, lines, offset);
1808
+ }
1809
+ goto finish;
1810
+ }
1811
+
1812
+ if (parse_debug_line(num_traces, traces,
1813
+ obj->debug_line.ptr,
1814
+ obj->debug_line.size,
1815
+ obj, lines, offset) == -1)
1816
+ goto fail;
1817
+
1818
+ finish:
1819
+ return dladdr_fbase;
1820
+ fail:
1821
+ return (uintptr_t)-1;
1822
+ }
1823
+ #else /* Mach-O */
1824
+ /* read file and fill lines */
1825
+ static uintptr_t
1826
+ fill_lines(int num_traces, void **traces, int check_debuglink,
1827
+ obj_info_t **objp, line_info_t *lines, int offset)
1828
+ {
1829
+ # ifdef __LP64__
1830
+ # define LP(x) x##_64
1831
+ # else
1832
+ # define LP(x) x
1833
+ # endif
1834
+ int fd;
1835
+ off_t filesize;
1836
+ char *file, *p = NULL;
1837
+ obj_info_t *obj = *objp;
1838
+ struct LP(mach_header) *header;
1839
+ uintptr_t dladdr_fbase = 0;
1840
+
1841
+ {
1842
+ char *s = binary_filename;
1843
+ char *base = strrchr(binary_filename, '/')+1;
1844
+ size_t max = PATH_MAX;
1845
+ size_t size = strlen(binary_filename);
1846
+ size_t basesize = size - (base - binary_filename);
1847
+ s += size;
1848
+ max -= size;
1849
+ p = s;
1850
+ size = strlcpy(s, ".dSYM/Contents/Resources/DWARF/", max);
1851
+ if (size == 0) goto fail;
1852
+ s += size;
1853
+ max -= size;
1854
+ if (max <= basesize) goto fail;
1855
+ memcpy(s, base, basesize);
1856
+ s[basesize] = 0;
1857
+
1858
+ fd = open(binary_filename, O_RDONLY);
1859
+ if (fd < 0) {
1860
+ *p = 0; /* binary_filename becomes original file name */
1861
+ fd = open(binary_filename, O_RDONLY);
1862
+ if (fd < 0) {
1863
+ goto fail;
1864
+ }
1865
+ }
1866
+ }
1867
+
1868
+ filesize = lseek(fd, 0, SEEK_END);
1869
+ if (filesize < 0) {
1870
+ int e = errno;
1871
+ close(fd);
1872
+ kprintf("lseek: %s\n", strerror(e));
1873
+ goto fail;
1874
+ }
1875
+ #if SIZEOF_OFF_T > SIZEOF_SIZE_T
1876
+ if (filesize > (off_t)SIZE_MAX) {
1877
+ close(fd);
1878
+ kprintf("Too large file %s\n", binary_filename);
1879
+ goto fail;
1880
+ }
1881
+ #endif
1882
+ lseek(fd, 0, SEEK_SET);
1883
+ /* async-signal unsafe */
1884
+ file = (char *)mmap(NULL, (size_t)filesize, PROT_READ, MAP_SHARED, fd, 0);
1885
+ if (file == MAP_FAILED) {
1886
+ int e = errno;
1887
+ close(fd);
1888
+ kprintf("mmap: %s\n", strerror(e));
1889
+ goto fail;
1890
+ }
1891
+ close(fd);
1892
+
1893
+ obj->mapped = file;
1894
+ obj->mapped_size = (size_t)filesize;
1895
+
1896
+ header = (struct LP(mach_header) *)file;
1897
+ if (header->magic == LP(MH_MAGIC)) {
1898
+ /* non universal binary */
1899
+ p = file;
1900
+ }
1901
+ else if (header->magic == FAT_CIGAM) {
1902
+ struct LP(mach_header) *mhp = _NSGetMachExecuteHeader();
1903
+ struct fat_header *fat = (struct fat_header *)file;
1904
+ char *q = file + sizeof(*fat);
1905
+ uint32_t nfat_arch = __builtin_bswap32(fat->nfat_arch);
1906
+ /* fprintf(stderr,"%d: fat:%s %d\n",__LINE__, binary_filename,nfat_arch); */
1907
+ for (uint32_t i = 0; i < nfat_arch; i++) {
1908
+ struct fat_arch *arch = (struct fat_arch *)q;
1909
+ cpu_type_t cputype = __builtin_bswap32(arch->cputype);
1910
+ cpu_subtype_t cpusubtype = __builtin_bswap32(arch->cpusubtype);
1911
+ uint32_t offset = __builtin_bswap32(arch->offset);
1912
+ /* fprintf(stderr,"%d: fat %d %x/%x %x/%x\n",__LINE__, i, mhp->cputype,mhp->cpusubtype, cputype,cpusubtype); */
1913
+ if (mhp->cputype == cputype &&
1914
+ (cpu_subtype_t)(mhp->cpusubtype & ~CPU_SUBTYPE_MASK) == cpusubtype) {
1915
+ p = file + offset;
1916
+ file = p;
1917
+ header = (struct LP(mach_header) *)p;
1918
+ if (header->magic == LP(MH_MAGIC)) {
1919
+ goto found_mach_header;
1920
+ }
1921
+ break;
1922
+ }
1923
+ q += sizeof(*arch);
1924
+ }
1925
+ kprintf("'%s' is not a Mach-O universal binary file!\n",binary_filename);
1926
+ close(fd);
1927
+ goto fail;
1928
+ }
1929
+ else {
1930
+ kprintf("'%s' is not a "
1931
+ # ifdef __LP64__
1932
+ "64"
1933
+ # else
1934
+ "32"
1935
+ # endif
1936
+ "-bit Mach-O file!\n",binary_filename);
1937
+ close(fd);
1938
+ goto fail;
1939
+ }
1940
+ found_mach_header:
1941
+ p += sizeof(*header);
1942
+
1943
+ for (uint32_t i = 0; i < (uint32_t)header->ncmds; i++) {
1944
+ struct load_command *lcmd = (struct load_command *)p;
1945
+ switch (lcmd->cmd) {
1946
+ case LP(LC_SEGMENT):
1947
+ {
1948
+ static const char *debug_section_names[] = {
1949
+ "__debug_abbrev",
1950
+ "__debug_info",
1951
+ "__debug_line",
1952
+ "__debug_ranges",
1953
+ "__debug_str"
1954
+ };
1955
+ struct LP(segment_command) *scmd = (struct LP(segment_command) *)lcmd;
1956
+ if (strcmp(scmd->segname, "__TEXT") == 0) {
1957
+ obj->vmaddr = scmd->vmaddr;
1958
+ }
1959
+ else if (strcmp(scmd->segname, "__DWARF") == 0) {
1960
+ p += sizeof(struct LP(segment_command));
1961
+ for (uint64_t i = 0; i < scmd->nsects; i++) {
1962
+ struct LP(section) *sect = (struct LP(section) *)p;
1963
+ p += sizeof(struct LP(section));
1964
+ for (int j=0; j < DWARF_SECTION_COUNT; j++) {
1965
+ struct dwarf_section *s = obj_dwarf_section_at(obj, j);
1966
+
1967
+ if (strcmp(sect->sectname, debug_section_names[j]) != 0)
1968
+ continue;
1969
+
1970
+ s->ptr = file + sect->offset;
1971
+ s->size = sect->size;
1972
+ s->flags = sect->flags;
1973
+ if (s->flags & SHF_COMPRESSED) {
1974
+ goto fail;
1975
+ }
1976
+ break;
1977
+ }
1978
+ }
1979
+ }
1980
+ }
1981
+ break;
1982
+
1983
+ case LC_SYMTAB:
1984
+ {
1985
+ struct symtab_command *cmd = (struct symtab_command *)lcmd;
1986
+ struct LP(nlist) *nl = (struct LP(nlist) *)(file + cmd->symoff);
1987
+ char *strtab = file + cmd->stroff, *sname = 0;
1988
+ uint32_t j;
1989
+ uintptr_t saddr = 0;
1990
+ /* kprintf("[%2d]: %x/symtab %p\n", i, cmd->cmd, p); */
1991
+ for (j = 0; j < cmd->nsyms; j++) {
1992
+ uintptr_t symsize, d;
1993
+ struct LP(nlist) *e = &nl[j];
1994
+ /* kprintf("[%2d][%4d]: %02x/%x/%x: %s %llx\n", i, j, e->n_type,e->n_sect,e->n_desc,strtab+e->n_un.n_strx,e->n_value); */
1995
+ if (e->n_type != N_FUN) continue;
1996
+ if (e->n_sect) {
1997
+ saddr = (uintptr_t)e->n_value + obj->base_addr - obj->vmaddr;
1998
+ sname = strtab + e->n_un.n_strx;
1999
+ /* kprintf("[%2d][%4d]: %02x/%x/%x: %s %llx\n", i, j, e->n_type,e->n_sect,e->n_desc,strtab+e->n_un.n_strx,e->n_value); */
2000
+ continue;
2001
+ }
2002
+ for (int k = offset; k < num_traces; k++) {
2003
+ d = (uintptr_t)traces[k] - saddr;
2004
+ symsize = e->n_value;
2005
+ /* kprintf("%lx %lx %lx\n",saddr,symsize,traces[k]); */
2006
+ if (lines[k].line > 0 || d > (uintptr_t)symsize)
2007
+ continue;
2008
+ /* fill symbol name and addr from .symtab */
2009
+ if (!lines[k].sname) lines[k].sname = sname;
2010
+ lines[k].saddr = saddr;
2011
+ lines[k].path = obj->path;
2012
+ lines[k].base_addr = obj->base_addr;
2013
+ }
2014
+ }
2015
+ }
2016
+ }
2017
+ p += lcmd->cmdsize;
2018
+ }
2019
+
2020
+ if (obj->debug_info.ptr && obj->debug_abbrev.ptr) {
2021
+ DebugInfoReader reader;
2022
+ debug_info_reader_init(&reader, obj);
2023
+ while (reader.p < reader.pend) {
2024
+ if (di_read_cu(&reader)) goto fail;
2025
+ debug_info_read(&reader, num_traces, traces, lines, offset);
2026
+ }
2027
+ }
2028
+
2029
+ if (parse_debug_line(num_traces, traces,
2030
+ obj->debug_line.ptr,
2031
+ obj->debug_line.size,
2032
+ obj, lines, offset) == -1)
2033
+ goto fail;
2034
+
2035
+ return dladdr_fbase;
2036
+ fail:
2037
+ return (uintptr_t)-1;
2038
+ }
2039
+ #endif
2040
+
2041
+ #define HAVE_MAIN_EXE_PATH
2042
+ #if defined(__FreeBSD__)
2043
+ # include <sys/sysctl.h>
2044
+ #endif
2045
+ /* ssize_t main_exe_path(void)
2046
+ *
2047
+ * store the path of the main executable to `binary_filename`,
2048
+ * and returns strlen(binary_filename).
2049
+ * it is NUL terminated.
2050
+ */
2051
+ #if defined(__linux__)
2052
+ static ssize_t
2053
+ main_exe_path(void)
2054
+ {
2055
+ # define PROC_SELF_EXE "/proc/self/exe"
2056
+ ssize_t len = readlink(PROC_SELF_EXE, binary_filename, PATH_MAX);
2057
+ if (len < 0) return 0;
2058
+ binary_filename[len] = 0;
2059
+ return len;
2060
+ }
2061
+ #elif defined(__FreeBSD__)
2062
+ static ssize_t
2063
+ main_exe_path(void)
2064
+ {
2065
+ int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
2066
+ size_t len = PATH_MAX;
2067
+ int err = sysctl(mib, 4, binary_filename, &len, NULL, 0);
2068
+ if (err) {
2069
+ kprintf("Can't get the path of ruby");
2070
+ return -1;
2071
+ }
2072
+ len--; /* sysctl sets strlen+1 */
2073
+ return len;
2074
+ }
2075
+ #elif defined(HAVE_LIBPROC_H)
2076
+ static ssize_t
2077
+ main_exe_path(void)
2078
+ {
2079
+ int len = proc_pidpath(getpid(), binary_filename, PATH_MAX);
2080
+ if (len == 0) return 0;
2081
+ binary_filename[len] = 0;
2082
+ return len;
2083
+ }
2084
+ #else
2085
+ #undef HAVE_MAIN_EXE_PATH
2086
+ #endif
2087
+
2088
+ static void
2089
+ print_line0(line_info_t *line, void *address)
2090
+ {
2091
+ uintptr_t addr = (uintptr_t)address;
2092
+ uintptr_t d = addr - line->saddr;
2093
+ if (!address) {
2094
+ /* inlined */
2095
+ if (line->dirname && line->dirname[0]) {
2096
+ kprintf("%s(%s) %s/%s:%d\n", line->path, line->sname, line->dirname, line->filename, line->line);
2097
+ }
2098
+ else {
2099
+ kprintf("%s(%s) %s:%d\n", line->path, line->sname, line->filename, line->line);
2100
+ }
2101
+ }
2102
+ else if (!line->path) {
2103
+ kprintf("[0x%"PRIxPTR"]\n", addr);
2104
+ }
2105
+ else if (!line->saddr || !line->sname) {
2106
+ kprintf("%s(0x%"PRIxPTR") [0x%"PRIxPTR"]\n", line->path, addr-line->base_addr, addr);
2107
+ }
2108
+ else if (line->line <= 0) {
2109
+ kprintf("%s(%s+0x%"PRIxPTR") [0x%"PRIxPTR"]\n", line->path, line->sname,
2110
+ d, addr);
2111
+ }
2112
+ else if (!line->filename) {
2113
+ kprintf("%s(%s+0x%"PRIxPTR") [0x%"PRIxPTR"] ???:%d\n", line->path, line->sname,
2114
+ d, addr, line->line);
2115
+ }
2116
+ else if (line->dirname && line->dirname[0]) {
2117
+ kprintf("%s(%s+0x%"PRIxPTR") [0x%"PRIxPTR"] %s/%s:%d\n", line->path, line->sname,
2118
+ d, addr, line->dirname, line->filename, line->line);
2119
+ }
2120
+ else {
2121
+ kprintf("%s(%s+0x%"PRIxPTR") [0x%"PRIxPTR"] %s:%d\n", line->path, line->sname,
2122
+ d, addr, line->filename, line->line);
2123
+ }
2124
+ }
2125
+
2126
+ static void
2127
+ print_line(line_info_t *line, void *address)
2128
+ {
2129
+ print_line0(line, address);
2130
+ if (line->next) {
2131
+ print_line(line->next, NULL);
2132
+ }
2133
+ }
2134
+
2135
+ void
2136
+ rb_dump_backtrace_with_lines(int num_traces, void **traces)
2137
+ {
2138
+ int i;
2139
+ /* async-signal unsafe */
2140
+ line_info_t *lines = (line_info_t *)calloc(num_traces, sizeof(line_info_t));
2141
+ obj_info_t *obj = NULL;
2142
+ /* 2 is NULL + main executable */
2143
+ void **dladdr_fbases = (void **)calloc(num_traces+2, sizeof(void *));
2144
+ #ifdef HAVE_MAIN_EXE_PATH
2145
+ char *main_path = NULL; /* used on printing backtrace */
2146
+ ssize_t len;
2147
+ if ((len = main_exe_path()) > 0) {
2148
+ main_path = (char *)alloca(len + 1);
2149
+ if (main_path) {
2150
+ uintptr_t addr;
2151
+ memcpy(main_path, binary_filename, len+1);
2152
+ append_obj(&obj);
2153
+ obj->path = main_path;
2154
+ addr = fill_lines(num_traces, traces, 1, &obj, lines, -1);
2155
+ if (addr != (uintptr_t)-1) {
2156
+ dladdr_fbases[0] = (void *)addr;
2157
+ }
2158
+ }
2159
+ }
2160
+ #endif
2161
+
2162
+ /* fill source lines by reading dwarf */
2163
+ for (i = 0; i < num_traces; i++) {
2164
+ Dl_info info;
2165
+ if (lines[i].line) continue;
2166
+ if (dladdr(traces[i], &info)) {
2167
+ const char *path;
2168
+ void **p;
2169
+
2170
+ /* skip symbols which is in already checked objects */
2171
+ /* if the binary is strip-ed, this may effect */
2172
+ for (p=dladdr_fbases; *p; p++) {
2173
+ if (*p == info.dli_fbase) {
2174
+ lines[i].path = info.dli_fname;
2175
+ lines[i].sname = info.dli_sname;
2176
+ goto next_line;
2177
+ }
2178
+ }
2179
+ *p = info.dli_fbase;
2180
+
2181
+ append_obj(&obj);
2182
+ obj->base_addr = (uintptr_t)info.dli_fbase;
2183
+ path = info.dli_fname;
2184
+ obj->path = path;
2185
+ lines[i].path = path;
2186
+ lines[i].sname = info.dli_sname;
2187
+ lines[i].saddr = (uintptr_t)info.dli_saddr;
2188
+ strlcpy(binary_filename, path, PATH_MAX);
2189
+ if (fill_lines(num_traces, traces, 1, &obj, lines, i) == (uintptr_t)-1)
2190
+ break;
2191
+ }
2192
+ next_line:
2193
+ continue;
2194
+ }
2195
+
2196
+ /* output */
2197
+ for (i = 0; i < num_traces; i++) {
2198
+ print_line(&lines[i], traces[i]);
2199
+
2200
+ /* FreeBSD's backtrace may show _start and so on */
2201
+ if (lines[i].sname && strcmp("main", lines[i].sname) == 0)
2202
+ break;
2203
+ }
2204
+
2205
+ /* free */
2206
+ while (obj) {
2207
+ obj_info_t *o = obj;
2208
+ for (i=0; i < DWARF_SECTION_COUNT; i++) {
2209
+ struct dwarf_section *s = obj_dwarf_section_at(obj, i);
2210
+ if (s->flags & SHF_COMPRESSED) {
2211
+ free(s->ptr);
2212
+ }
2213
+ }
2214
+ if (obj->mapped_size) {
2215
+ munmap(obj->mapped, obj->mapped_size);
2216
+ }
2217
+ obj = o->next;
2218
+ free(o);
2219
+ }
2220
+ for (i = 0; i < num_traces; i++) {
2221
+ line_info_t *line = lines[i].next;
2222
+ while (line) {
2223
+ line_info_t *l = line;
2224
+ line = line->next;
2225
+ free(l);
2226
+ }
2227
+ }
2228
+ free(lines);
2229
+ free(dladdr_fbases);
2230
+ }
2231
+
2232
+ /* From FreeBSD's lib/libstand/printf.c */
2233
+ /*-
2234
+ * Copyright (c) 1986, 1988, 1991, 1993
2235
+ * The Regents of the University of California. All rights reserved.
2236
+ * (c) UNIX System Laboratories, Inc.
2237
+ * All or some portions of this file are derived from material licensed
2238
+ * to the University of California by American Telephone and Telegraph
2239
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
2240
+ * the permission of UNIX System Laboratories, Inc.
2241
+ *
2242
+ * Redistribution and use in source and binary forms, with or without
2243
+ * modification, are permitted provided that the following conditions
2244
+ * are met:
2245
+ * 1. Redistributions of source code must retain the above copyright
2246
+ * notice, this list of conditions and the following disclaimer.
2247
+ * 2. Redistributions in binary form must reproduce the above copyright
2248
+ * notice, this list of conditions and the following disclaimer in the
2249
+ * documentation and/or other materials provided with the distribution.
2250
+ * 4. Neither the name of the University nor the names of its contributors
2251
+ * may be used to endorse or promote products derived from this software
2252
+ * without specific prior written permission.
2253
+ *
2254
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2255
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2256
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2257
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2258
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2259
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2260
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2261
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2262
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2263
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2264
+ * SUCH DAMAGE.
2265
+ *
2266
+ * @(#)subr_prf.c 8.3 (Berkeley) 1/21/94
2267
+ */
2268
+
2269
+ #include <stdarg.h>
2270
+ #define MAXNBUF (sizeof(intmax_t) * CHAR_BIT + 1)
2271
+ static inline int toupper(int c) { return ('A' <= c && c <= 'Z') ? (c&0x5f) : c; }
2272
+ #define hex2ascii(hex) (hex2ascii_data[hex])
2273
+ static const char hex2ascii_data[] = "0123456789abcdefghijklmnopqrstuvwxyz";
2274
+ static inline int imax(int a, int b) { return (a > b ? a : b); }
2275
+ static int kvprintf(char const *fmt, void (*func)(int), void *arg, int radix, va_list ap);
2276
+
2277
+ static void putce(int c)
2278
+ {
2279
+ char s[1];
2280
+ ssize_t ret;
2281
+
2282
+ s[0] = (char)c;
2283
+ ret = write(2, s, 1);
2284
+ (void)ret;
2285
+ }
2286
+
2287
+ static int
2288
+ kprintf(const char *fmt, ...)
2289
+ {
2290
+ va_list ap;
2291
+ int retval;
2292
+
2293
+ va_start(ap, fmt);
2294
+ retval = kvprintf(fmt, putce, NULL, 10, ap);
2295
+ va_end(ap);
2296
+ return retval;
2297
+ }
2298
+
2299
+ /*
2300
+ * Put a NUL-terminated ASCII number (base <= 36) in a buffer in reverse
2301
+ * order; return an optional length and a pointer to the last character
2302
+ * written in the buffer (i.e., the first character of the string).
2303
+ * The buffer pointed to by `nbuf' must have length >= MAXNBUF.
2304
+ */
2305
+ static char *
2306
+ ksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper)
2307
+ {
2308
+ char *p, c;
2309
+
2310
+ p = nbuf;
2311
+ *p = '\0';
2312
+ do {
2313
+ c = hex2ascii(num % base);
2314
+ *++p = upper ? toupper(c) : c;
2315
+ } while (num /= base);
2316
+ if (lenp)
2317
+ *lenp = (int)(p - nbuf);
2318
+ return (p);
2319
+ }
2320
+
2321
+ /*
2322
+ * Scaled down version of printf(3).
2323
+ *
2324
+ * Two additional formats:
2325
+ *
2326
+ * The format %b is supported to decode error registers.
2327
+ * Its usage is:
2328
+ *
2329
+ * printf("reg=%b\n", regval, "<base><arg>*");
2330
+ *
2331
+ * where <base> is the output base expressed as a control character, e.g.
2332
+ * \10 gives octal; \20 gives hex. Each arg is a sequence of characters,
2333
+ * the first of which gives the bit number to be inspected (origin 1), and
2334
+ * the next characters (up to a control character, i.e. a character <= 32),
2335
+ * give the name of the register. Thus:
2336
+ *
2337
+ * kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
2338
+ *
2339
+ * would produce output:
2340
+ *
2341
+ * reg=3<BITTWO,BITONE>
2342
+ *
2343
+ * XXX: %D -- Hexdump, takes pointer and separator string:
2344
+ * ("%6D", ptr, ":") -> XX:XX:XX:XX:XX:XX
2345
+ * ("%*D", len, ptr, " " -> XX XX XX XX ...
2346
+ */
2347
+ static int
2348
+ kvprintf(char const *fmt, void (*func)(int), void *arg, int radix, va_list ap)
2349
+ {
2350
+ #define PCHAR(c) {int cc=(c); if (func) (*func)(cc); else *d++ = cc; retval++; }
2351
+ char nbuf[MAXNBUF];
2352
+ char *d;
2353
+ const char *p, *percent, *q;
2354
+ unsigned char *up;
2355
+ int ch, n;
2356
+ uintmax_t num;
2357
+ int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot;
2358
+ int cflag, hflag, jflag, tflag, zflag;
2359
+ int dwidth, upper;
2360
+ char padc;
2361
+ int stop = 0, retval = 0;
2362
+
2363
+ num = 0;
2364
+ if (!func)
2365
+ d = (char *) arg;
2366
+ else
2367
+ d = NULL;
2368
+
2369
+ if (fmt == NULL)
2370
+ fmt = "(fmt null)\n";
2371
+
2372
+ if (radix < 2 || radix > 36)
2373
+ radix = 10;
2374
+
2375
+ for (;;) {
2376
+ padc = ' ';
2377
+ width = 0;
2378
+ while ((ch = (unsigned char)*fmt++) != '%' || stop) {
2379
+ if (ch == '\0')
2380
+ return (retval);
2381
+ PCHAR(ch);
2382
+ }
2383
+ percent = fmt - 1;
2384
+ qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0;
2385
+ sign = 0; dot = 0; dwidth = 0; upper = 0;
2386
+ cflag = 0; hflag = 0; jflag = 0; tflag = 0; zflag = 0;
2387
+ reswitch: switch (ch = (unsigned char)*fmt++) {
2388
+ case '.':
2389
+ dot = 1;
2390
+ goto reswitch;
2391
+ case '#':
2392
+ sharpflag = 1;
2393
+ goto reswitch;
2394
+ case '+':
2395
+ sign = 1;
2396
+ goto reswitch;
2397
+ case '-':
2398
+ ladjust = 1;
2399
+ goto reswitch;
2400
+ case '%':
2401
+ PCHAR(ch);
2402
+ break;
2403
+ case '*':
2404
+ if (!dot) {
2405
+ width = va_arg(ap, int);
2406
+ if (width < 0) {
2407
+ ladjust = !ladjust;
2408
+ width = -width;
2409
+ }
2410
+ } else {
2411
+ dwidth = va_arg(ap, int);
2412
+ }
2413
+ goto reswitch;
2414
+ case '0':
2415
+ if (!dot) {
2416
+ padc = '0';
2417
+ goto reswitch;
2418
+ }
2419
+ case '1': case '2': case '3': case '4':
2420
+ case '5': case '6': case '7': case '8': case '9':
2421
+ for (n = 0;; ++fmt) {
2422
+ n = n * 10 + ch - '0';
2423
+ ch = *fmt;
2424
+ if (ch < '0' || ch > '9')
2425
+ break;
2426
+ }
2427
+ if (dot)
2428
+ dwidth = n;
2429
+ else
2430
+ width = n;
2431
+ goto reswitch;
2432
+ case 'b':
2433
+ num = (unsigned int)va_arg(ap, int);
2434
+ p = va_arg(ap, char *);
2435
+ for (q = ksprintn(nbuf, num, *p++, NULL, 0); *q;)
2436
+ PCHAR(*q--);
2437
+
2438
+ if (num == 0)
2439
+ break;
2440
+
2441
+ for (tmp = 0; *p;) {
2442
+ n = *p++;
2443
+ if (num & (1 << (n - 1))) {
2444
+ PCHAR(tmp ? ',' : '<');
2445
+ for (; (n = *p) > ' '; ++p)
2446
+ PCHAR(n);
2447
+ tmp = 1;
2448
+ } else
2449
+ for (; *p > ' '; ++p)
2450
+ continue;
2451
+ }
2452
+ if (tmp)
2453
+ PCHAR('>');
2454
+ break;
2455
+ case 'c':
2456
+ PCHAR(va_arg(ap, int));
2457
+ break;
2458
+ case 'D':
2459
+ up = va_arg(ap, unsigned char *);
2460
+ p = va_arg(ap, char *);
2461
+ if (!width)
2462
+ width = 16;
2463
+ while(width--) {
2464
+ PCHAR(hex2ascii(*up >> 4));
2465
+ PCHAR(hex2ascii(*up & 0x0f));
2466
+ up++;
2467
+ if (width)
2468
+ for (q=p;*q;q++)
2469
+ PCHAR(*q);
2470
+ }
2471
+ break;
2472
+ case 'd':
2473
+ case 'i':
2474
+ base = 10;
2475
+ sign = 1;
2476
+ goto handle_sign;
2477
+ case 'h':
2478
+ if (hflag) {
2479
+ hflag = 0;
2480
+ cflag = 1;
2481
+ } else
2482
+ hflag = 1;
2483
+ goto reswitch;
2484
+ case 'j':
2485
+ jflag = 1;
2486
+ goto reswitch;
2487
+ case 'l':
2488
+ if (lflag) {
2489
+ lflag = 0;
2490
+ qflag = 1;
2491
+ } else
2492
+ lflag = 1;
2493
+ goto reswitch;
2494
+ case 'n':
2495
+ if (jflag)
2496
+ *(va_arg(ap, intmax_t *)) = retval;
2497
+ else if (qflag)
2498
+ *(va_arg(ap, int64_t *)) = retval;
2499
+ else if (lflag)
2500
+ *(va_arg(ap, long *)) = retval;
2501
+ else if (zflag)
2502
+ *(va_arg(ap, size_t *)) = retval;
2503
+ else if (hflag)
2504
+ *(va_arg(ap, short *)) = retval;
2505
+ else if (cflag)
2506
+ *(va_arg(ap, char *)) = retval;
2507
+ else
2508
+ *(va_arg(ap, int *)) = retval;
2509
+ break;
2510
+ case 'o':
2511
+ base = 8;
2512
+ goto handle_nosign;
2513
+ case 'p':
2514
+ base = 16;
2515
+ sharpflag = (width == 0);
2516
+ sign = 0;
2517
+ num = (uintptr_t)va_arg(ap, void *);
2518
+ goto number;
2519
+ case 'q':
2520
+ qflag = 1;
2521
+ goto reswitch;
2522
+ case 'r':
2523
+ base = radix;
2524
+ if (sign)
2525
+ goto handle_sign;
2526
+ goto handle_nosign;
2527
+ case 's':
2528
+ p = va_arg(ap, char *);
2529
+ if (p == NULL)
2530
+ p = "(null)";
2531
+ if (!dot)
2532
+ n = (int)strlen (p);
2533
+ else
2534
+ for (n = 0; n < dwidth && p[n]; n++)
2535
+ continue;
2536
+
2537
+ width -= n;
2538
+
2539
+ if (!ladjust && width > 0)
2540
+ while (width--)
2541
+ PCHAR(padc);
2542
+ while (n--)
2543
+ PCHAR(*p++);
2544
+ if (ladjust && width > 0)
2545
+ while (width--)
2546
+ PCHAR(padc);
2547
+ break;
2548
+ case 't':
2549
+ tflag = 1;
2550
+ goto reswitch;
2551
+ case 'u':
2552
+ base = 10;
2553
+ goto handle_nosign;
2554
+ case 'X':
2555
+ upper = 1;
2556
+ case 'x':
2557
+ base = 16;
2558
+ goto handle_nosign;
2559
+ case 'y':
2560
+ base = 16;
2561
+ sign = 1;
2562
+ goto handle_sign;
2563
+ case 'z':
2564
+ zflag = 1;
2565
+ goto reswitch;
2566
+ handle_nosign:
2567
+ sign = 0;
2568
+ if (jflag)
2569
+ num = va_arg(ap, uintmax_t);
2570
+ else if (qflag)
2571
+ num = va_arg(ap, uint64_t);
2572
+ else if (tflag)
2573
+ num = va_arg(ap, ptrdiff_t);
2574
+ else if (lflag)
2575
+ num = va_arg(ap, unsigned long);
2576
+ else if (zflag)
2577
+ num = va_arg(ap, size_t);
2578
+ else if (hflag)
2579
+ num = (unsigned short)va_arg(ap, int);
2580
+ else if (cflag)
2581
+ num = (unsigned char)va_arg(ap, int);
2582
+ else
2583
+ num = va_arg(ap, unsigned int);
2584
+ goto number;
2585
+ handle_sign:
2586
+ if (jflag)
2587
+ num = va_arg(ap, intmax_t);
2588
+ else if (qflag)
2589
+ num = va_arg(ap, int64_t);
2590
+ else if (tflag)
2591
+ num = va_arg(ap, ptrdiff_t);
2592
+ else if (lflag)
2593
+ num = va_arg(ap, long);
2594
+ else if (zflag)
2595
+ num = va_arg(ap, ssize_t);
2596
+ else if (hflag)
2597
+ num = (short)va_arg(ap, int);
2598
+ else if (cflag)
2599
+ num = (char)va_arg(ap, int);
2600
+ else
2601
+ num = va_arg(ap, int);
2602
+ number:
2603
+ if (sign && (intmax_t)num < 0) {
2604
+ neg = 1;
2605
+ num = -(intmax_t)num;
2606
+ }
2607
+ p = ksprintn(nbuf, num, base, &n, upper);
2608
+ tmp = 0;
2609
+ if (sharpflag && num != 0) {
2610
+ if (base == 8)
2611
+ tmp++;
2612
+ else if (base == 16)
2613
+ tmp += 2;
2614
+ }
2615
+ if (neg)
2616
+ tmp++;
2617
+
2618
+ if (!ladjust && padc == '0')
2619
+ dwidth = width - tmp;
2620
+ width -= tmp + imax(dwidth, n);
2621
+ dwidth -= n;
2622
+ if (!ladjust)
2623
+ while (width-- > 0)
2624
+ PCHAR(' ');
2625
+ if (neg)
2626
+ PCHAR('-');
2627
+ if (sharpflag && num != 0) {
2628
+ if (base == 8) {
2629
+ PCHAR('0');
2630
+ } else if (base == 16) {
2631
+ PCHAR('0');
2632
+ PCHAR('x');
2633
+ }
2634
+ }
2635
+ while (dwidth-- > 0)
2636
+ PCHAR('0');
2637
+
2638
+ while (*p)
2639
+ PCHAR(*p--);
2640
+
2641
+ if (ladjust)
2642
+ while (width-- > 0)
2643
+ PCHAR(' ');
2644
+
2645
+ break;
2646
+ default:
2647
+ while (percent < fmt)
2648
+ PCHAR(*percent++);
2649
+ /*
2650
+ * Since we ignore an formatting argument it is no
2651
+ * longer safe to obey the remaining formatting
2652
+ * arguments as the arguments will no longer match
2653
+ * the format specs.
2654
+ */
2655
+ stop = 1;
2656
+ break;
2657
+ }
2658
+ }
2659
+ #undef PCHAR
2660
+ }
2661
+ #else /* defined(USE_ELF) */
2662
+ #error not supported
2663
+ #endif