sigcdump 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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