1// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
2//
3// SPDX-License-Identifier: GPL-3.0-or-later
4
5#include <assert.h>
6#include <fnmatch.h>
7#include <limits.h>
8#include <linux/net.h>
9#include <sys/socket.h>
10#include <sys/types.h>
11#include <sys/ptrace.h>
12#include <sys/syscall.h>
13#include <sys/mman.h>
14#include <sys/wait.h>
15#include <sys/un.h>
16#include <sys/user.h>
17
18#if !defined(__sw_64) && !defined(__aarch64__)
19#include <capstone/capstone.h>
20#endif
21
22#if defined(__i386__) || defined(__x86_64__)
23#include <libunwind-ptrace.h>
24#endif
25
26#include <string>
27#include <memory>
28
29#include "cpu.h"
30#include "debug.h"
31#include "elf_helper.h"
32
33using namespace std;
34
35int write_mem(int pid, uintptr_t addr, const void* buf, int buf_size)
36{
37 int nwritten = 0;
38 // ptrace operates on the word size of the host, so we really do want
39 // to use sizes of host types here.
40 uintptr_t word_size = sizeof(long);
41
42 errno = 0;
43
44 // Only write aligned words. This ensures we can always write the last
45 // byte before an unmapped region.
46 while (nwritten < buf_size) {
47 uintptr_t start = addr + nwritten;
48 uintptr_t start_word = start & ~(word_size - 1);
49 uintptr_t end_word = start_word + word_size;
50 uintptr_t length = min(end_word - start, uintptr_t(buf_size - nwritten));
51
52 long v;
53 if (length < word_size) {
54 v = ptrace(PTRACE_PEEKDATA, pid, start_word, nullptr);
55 if (errno) {
56 break;
57 }
58 }
59
60 memcpy(reinterpret_cast<uint8_t*>(&v) + (start - start_word),
61 static_cast<const uint8_t*>(buf) + nwritten, length);
62 ptrace(PTRACE_POKEDATA, pid, start_word, reinterpret_cast<void*>(v));
63 nwritten += length;
64 }
65
66 return nwritten;
67}
68
69int read_mem(int tid, uintptr_t addr, void* buf, int buf_size)
70{
71 int nread = 0;
72 // ptrace operates on the word size of the host, so we really do want
73 // to use sizes of host types here.
74 uintptr_t word_size = sizeof(long);
75 // Only read aligned words. This ensures we can always read the last
76 // byte before an unmapped region.
77 uintptr_t start_word = addr & ~(word_size - 1);
78 uintptr_t end_word = (addr + buf_size) & ~(word_size - 1);
79
80 errno = 0;
81 if (start_word < addr) {
82 // the first unaligned part
83 long v = ptrace(PTRACE_PEEKDATA, tid, start_word, nullptr);
84 long offset = (addr - start_word);
85 start_word += word_size;
86 nread = start_word - addr;
87 if (nread > buf_size) nread = buf_size;
88 memcpy(static_cast<uint8_t*>(buf),
89 reinterpret_cast<uint8_t*>(&v) + offset, nread);
90 }
91
92 while (start_word < end_word) {
93 long v = ptrace(PTRACE_PEEKDATA, tid, start_word, nullptr);
94 if (errno) {
95 break;
96 }
97 start_word += word_size;
98 memcpy(static_cast<uint8_t*>(buf) + nread,
99 reinterpret_cast<uint8_t*>(&v), word_size);
100 nread += word_size;
101 }
102
103 if (nread < buf_size) {
104 // the last unaligned part
105 long v = ptrace(PTRACE_PEEKDATA, tid, start_word, nullptr);
106 memcpy(static_cast<uint8_t*>(buf) + nread,
107 reinterpret_cast<uint8_t*>(&v), buf_size - nread);
108 nread = buf_size;
109 }
110
111 return nread;
112}
113
114int gdb_disass(int pid, void* base, int len)
115{
116#if defined(__sw_64) || defined(__aarch64__)
117 return -1;
118#else
119 csh handle;
120 cs_insn* insn = NULL;
121 uintptr_t address = (uintptr_t)base;
122 string codestr('0', len);
123 uint8_t* code = (uint8_t*)codestr.data();
124 size_t code_size = len;
125
126 int got = read_mem(pid, address, code, code_size);
127 if (got < (int)code_size) {
128 return -1;
129 }
130
131#if defined(__x86_64__)
132 if (cs_open(CS_ARCH_X86, cs_mode(CS_MODE_64), &handle) != CS_ERR_OK) {
133#elif defined(__mips64)
134 if (cs_open(CS_ARCH_MIPS, cs_mode(CS_MODE_MIPS64|CS_MODE_LITTLE_ENDIAN),
135 &handle) != CS_ERR_OK) {
136#else
137 if (1) {
138#endif
139 return -2;
140 }
141
142 // allocate memory cache for 1 instruction, to be used by cs_disasm_iter later.
143 insn = cs_malloc(handle);
144
145 /*Some mips struction on loonson not support by libcapstone
146 use this statement maybe better decode*/
147 cs_option(handle, CS_OPT_SKIPDATA, CS_OPT_ON);
148
149 // disassemble one instruction a time & store the result into @insn variable above
150 while(cs_disasm_iter(handle, (const uint8_t**)&code, &code_size, &address, insn))
151 {
152 // analyze disassembled instruction in @insn variable ...
153 // NOTE: @code, @code_size & @address variables are all updated
154 // to point to the next instruction after each iteration.
155
156 printf("0x%" PRIx64 ":\t%s\t%s\n",
157 insn->address, insn->mnemonic, insn->op_str);
158
159 // print implicit registers used by this instruction
160 cs_detail* detail = insn->detail;
161 if (!detail) continue;
162
163 if (detail->regs_read_count > 0) {
164 printf("\tImplicit registers read: ");
165 for (int n = 0; n < detail->regs_read_count; n++) {
166 printf("%s ", cs_reg_name(handle, detail->regs_read[n]));
167 }
168 printf("\n");
169 }
170
171 // print implicit registers modified by this instruction
172 if (detail->regs_write_count > 0) {
173 printf("\tImplicit registers modified: ");
174 for (int n = 0; n < detail->regs_write_count; n++) {
175 printf("%s ", cs_reg_name(handle, detail->regs_write[n]));
176 }
177 printf("\n");
178 }
179
180 // print the groups this instruction belong to
181 if (detail->groups_count > 0) {
182 printf("\tThis instruction belongs to groups: ");
183 for (int n = 0; n < detail->groups_count; n++) {
184 printf("%s ", cs_group_name(handle, detail->groups[n]));
185 }
186 printf("\n");
187 }
188 }
189
190 // release the cache memory when done
191 cs_free(insn, 1);
192 cs_close(&handle);
193 return 0;
194#endif
195}
196
197int gdb_pause(pid_t pid)
198{
199 int ret = ptrace(PTRACE_INTERRUPT, pid, nullptr, nullptr);
200 if (ret < 0) {
201 return -errno;
202 }
203
204 return 0;
205}
206
207// used by gdb console to debug dead-lock in recording
208int gdb_cont(pid_t pid)
209{
210 int ret = ptrace(PTRACE_CONT, pid, nullptr, nullptr);
211 if (ret < 0) {
212 return -errno;
213 }
214
215 return 0;
216}
217
218int gdb_step(int pid)
219{
220 int ret = ptrace(PTRACE_SINGLESTEP, pid, nullptr, nullptr);
221 if (ret < 0) {
222 return -errno;
223 }
224
225 return 0;
226}
227
228int gdb_bt(int tid)
229{
230#if defined(__i386__) || defined(__x86_64__)
231#define MAX_STACK_FRAME 64
232
233 unw_addr_space_t unwind_as;
234 struct UPT_info* ui = nullptr;
235 int n = 0, ret;
236 unw_cursor_t cursor;
237 unw_proc_info_t pi;
238 unw_word_t ip, sp, start_ip = 0, off;
239 char buf[512];
240
241 unwind_as = unw_create_addr_space (&_UPT_accessors, 0);
242 if (!unwind_as) {
243 printf("libunwind.unw_create_addr_space() failed\n");
244 return -1;
245 }
246
247 ui = reinterpret_cast<struct UPT_info*>(_UPT_create(tid));
248 ret = unw_init_remote (&cursor, unwind_as, ui);
249 if (ret < 0) {
250 printf("unw_init_remote() failed: pause first then try again, ret=%d\n", ret);
251 _UPT_destroy (ui);
252 return -2;
253 }
254
255 do {
256 if ((ret = unw_get_reg (&cursor, UNW_REG_IP, &ip)) < 0 ||
257 (ret = unw_get_reg (&cursor, UNW_REG_SP, &sp)) < 0) {
258 printf("unw_get_reg failed: ret=%d\n", ret);
259 break;
260 }
261
262 if (n == 0) start_ip = ip;
263
264 buf[0] = '\0';
265 unw_get_proc_name (&cursor, buf, sizeof (buf), &off);
266
267 if ((ret = unw_get_proc_info (&cursor, &pi)) < 0) {
268 printf("unw_get_proc_info(%lx)failed: ret=%d\n", ip, ret);
269 break;
270 }
271 printf("\t[%d \t]ip=%-16lx\tsp=%-16lx\t%s+%lx\n", n, ip, sp, buf, off);
272
273 ret = unw_step (&cursor);
274 if (ret < 0) {
275 unw_get_reg (&cursor, UNW_REG_IP, &ip);
276 printf("FAILURE: unw_step() returned %d, for ip=%lx\n", ret, ip);
277 break;
278 }
279
280 if (++n > MAX_STACK_FRAME) {
281 /* guard against bad unwind info in old libraries... */
282 printf("too deeply nested---assuming bogus unwind (start ip=%lx)\n", start_ip);
283 break;
284 }
285 }
286 while (ret > 0);
287
288 _UPT_destroy (ui);
289 if (unwind_as) {
290 unw_destroy_addr_space (unwind_as);
291 unwind_as = nullptr;
292 }
293#elif defined(__mips__) || defined(__sw_64) || defined(__aarch64__)
294 USER_REGS regs;
295 printf("\ndump register:\n");
296 gdb_reg(tid, &regs);
297 printf("\ndump memory of pc:\n");
298 gdb_mem(tid, (void*)regs.pc, 256, 1);
299 printf("\ndump memory of sp:\n");
300 gdb_mem(tid, (void*)regs.sp, 256, 1);
301#else
302 printf("not implement in your arch\n");
303#endif
304
305 return 0;
306}
307
308static unsigned int copy_print_char (char* out, const unsigned char* buf, unsigned int count)
309{
310 unsigned int i = 0;
311 while (i<count)
312 {
313 if (buf[i] < 0x20 || buf[i] > 0x7f)
314 {
315 out[i] = '.';
316 }
317 else
318 {
319 out[i] = buf[i];
320 }
321 ++i;
322 }
323 out[i++] = '\n';
324
325 return i;
326}
327
328static void print_bytes(const void* buffer, int total)
329{
330 char* str = NULL;
331 int i = 0;
332 int j = 0;
333 unsigned char* buf = (unsigned char*)buffer;
334 int count = total;
335 unique_ptr<char[]> outbuf = make_unique<char[]>(count*4 + (count+15)/16*2 + 48);
336
337 str = outbuf.get();
338
339 while ( i<count )
340 {
341 j += sprintf(str+j, "%02x ", buf[i] );
342
343 ++i;
344 if ( !( i&15 ) )
345 {
346 str[j++] = ' ';
347 j += copy_print_char (str+j, buf+i-16, 16);
348 }
349 }
350
351 if ( count&15 )
352 {
353 i = count&15; //left
354 memset (str+j, 0x20, (16-i)*3 + 1 );
355 j += (16-i)*3 + 1;
356 j += copy_print_char (str+j, buf+count-i, i);
357 }
358 str[j] = 0;
359
360 printf("%s", str);
361}
362
363static char hex2char(unsigned char hex)
364{
365 if (hex<0xa) return hex+'0';
366 else return hex-0xa+'a';
367}
368
369static void hex2str2(unsigned char* hex, int size, char* str)
370{
371 int i = 0;
372 char* walk = str;
373 for (;i<size;)
374 {
375 walk[0] = hex2char(hex[2*i+1]>>4);
376 walk[1] = hex2char(hex[2*i+1]&0xf);
377 walk[2] = hex2char(hex[2*i]>>4);
378 walk[3] = hex2char(hex[2*i]&0xf);
379 walk[4] = 0x20;
380 ++i;
381 walk += 5;
382 if (!(i & 7)) {
383 *walk++ = '\n';
384 }
385 }
386
387 *walk = 0;
388}
389
390static void hex2str4(unsigned char* hex, int size, char* str)
391{
392 int i = 0;
393 char* walk = str;
394 for (;i<size;)
395 {
396 walk[0] = hex2char(hex[4*i+3]>>4);
397 walk[1] = hex2char(hex[4*i+3]&0xf);
398 walk[2] = hex2char(hex[4*i+2]>>4);
399 walk[3] = hex2char(hex[4*i+2]&0xf);
400 walk[4] = hex2char(hex[4*i+1]>>4);
401 walk[5] = hex2char(hex[4*i+1]&0xf);
402 walk[6] = hex2char(hex[4*i]>>4);
403 walk[7] = hex2char(hex[4*i]&0xf);
404 walk[8] = 0x20;
405 ++i;
406 walk += 9;
407 if (!(i&3)) {
408 *walk++ = '\n';
409 }
410 }
411
412 *walk = 0;
413}
414
415static void hex2str8(unsigned char* hex, int size, char* str)
416{
417 int i = 0;
418 char* walk = str;
419 for (;i<size;)
420 {
421 walk[0 ] = hex2char(hex[8*i+7]>>4);
422 walk[1 ] = hex2char(hex[8*i+7]&0xf);
423 walk[2 ] = hex2char(hex[8*i+6]>>4);
424 walk[3 ] = hex2char(hex[8*i+6]&0xf);
425 walk[4 ] = hex2char(hex[8*i+5]>>4);
426 walk[5 ] = hex2char(hex[8*i+5]&0xf);
427 walk[6 ] = hex2char(hex[8*i+4]>>4);
428 walk[7 ] = hex2char(hex[8*i+4]&0xf);
429 walk[8 ] = hex2char(hex[8*i+3]>>4);
430 walk[9 ] = hex2char(hex[8*i+3]&0xf);
431 walk[10] = hex2char(hex[8*i+2]>>4);
432 walk[11] = hex2char(hex[8*i+2]&0xf);
433 walk[12] = hex2char(hex[8*i+1]>>4);
434 walk[13] = hex2char(hex[8*i+1]&0xf);
435 walk[14] = hex2char(hex[8*i]>>4);
436 walk[15] = hex2char(hex[8*i]&0xf);
437 walk[16] = 0x20;
438 ++i;
439 walk += 17;
440 if (!(i&1)) {
441 *walk++ = '\n';
442 }
443 }
444
445 *walk = 0;
446}
447
448static void print_short(const void* buffer, int total)
449{
450 int count = total/sizeof(short);
451 unique_ptr<char[]> outbuf = make_unique<char[]>(count*5 + count/8 + 32);
452 hex2str2((unsigned char*)buffer, count, outbuf.get());
453 printf("%s", outbuf.get());
454}
455
456static void print_word(const void* buffer, int total)
457{
458 int count = total/sizeof(int);
459 unique_ptr<char[]> outbuf = make_unique<char[]>(count*9 + count/4 + 32);
460 hex2str4((unsigned char*)buffer, count, outbuf.get());
461 printf("%s", outbuf.get());
462}
463
464static void print_dword(const void* buffer, int total)
465{
466 int count = total/sizeof(long);
467 unique_ptr<char[]> outbuf = make_unique<char[]>(count*17 + count/2 + 32);
468 hex2str8((unsigned char*)buffer, count, outbuf.get());
469 printf("%s", outbuf.get());
470}
471
472int gdb_mem(int pid, void* base, int len, int group)
473{
474 uintptr_t address = (uintptr_t)base;
475 unique_ptr<char[]> buffer = make_unique<char[]>(len);
476 void* code = buffer.get();
477 int got = read_mem(pid, address, code, len);
478 if (got < 1) {
479 printf("failed to read memory from:%lx,%d\n", address, len);
480 return -1;
481 }
482
483 len = got;
484 switch(group) {
485 case 1:
486 print_bytes(code, len);
487 break;
488 case 2:
489 print_short(code, len);
490 break;
491 case 4:
492 print_word(code, len);
493 break;
494 case 8:
495 print_dword(code, len);
496 break;
497 default:
498 break;
499 }
500
501 return len;
502}
503
504int gdb_reg(int tid, USER_REGS* out)
505{
506 USER_REGS regs;
507
508#if defined(__aarch64__)
509 static struct iovec io = {
510 .iov_base = &regs,
511 .iov_len = sizeof(regs)
512 };
513 if (ptrace(PTRACE_GETREGSET, tid, NT_PRSTATUS, &io) < 0) {
514#else
515 if (ptrace(PTRACE_GETREGS, tid, nullptr, &regs) < 0) {
516#endif
517 return -errno;
518 }
519
520#if defined(__i386__)
521#error unspport get_cpu_context
522#elif defined(__x86_64__)
523 printf("\trip=%-16llx\n", regs.rip);
524 printf("\trbp=%-16llx\n", regs.rbp);
525 printf("\trsp=%-16llx\n", regs.rsp);
526
527 printf("\trax=%-16llx\n", regs.rax);
528 printf("\trbx=%-16llx\n", regs.rbx);
529
530 printf("\trdi=%-16llx\n", regs.rdi);
531 printf("\trsi=%-16llx\n", regs.rsi);
532 printf("\trdx=%-16llx\n", regs.rdx);
533 printf("\trcx=%-16llx\n", regs.rcx);
534 printf("\tr8=%-16llx\n", regs.r8);
535 printf("\tr9=%-16llx\n", regs.r9);
536
537 printf("\tr10=%-16llx\n", regs.r10);
538 printf("\tr11=%-16llx\n", regs.r11);
539 printf("\tr12=%-16llx\n", regs.r12);
540 printf("\tr13=%-16llx\n", regs.r13);
541 printf("\tr14=%-16llx\n", regs.r14);
542 printf("\tr15=%-16llx\n", regs.r15);
543#elif defined(__mips__) || defined(__mips64)
544 printf("\tat=%-16lx\n", regs.at);
545 printf("\tv0=%-16lx\n", regs.v0);
546 printf("\tv1=%-16lx\n", regs.v1);
547 printf("\ta0=%-16lx\n", regs.a0);
548 printf("\ta1=%-16lx\n", regs.a1);
549 printf("\ta2=%-16lx\n", regs.a2);
550 printf("\ta3=%-16lx\n", regs.a3);
551
552#if _MIPS_SIM != _ABIO32
553 printf("\ta4=%-16lx\n", regs.a4);
554 printf("\ta5=%-16lx\n", regs.a5);
555 printf("\ta6=%-16lx\n", regs.a6);
556 printf("\ta7=%-16lx\n", regs.a7);
557 printf("\tt0=%-16lx\n", regs.t0);
558 printf("\tt1=%-16lx\n", regs.t1);
559 printf("\tt2=%-16lx\n", regs.t2);
560 printf("\tt3=%-16lx\n", regs.t3);
561#else /* if _MIPS_SIM == _ABIO32 */
562 printf("\tt0=%-16lx\n", regs.t0);
563 printf("\tt1=%-16lx\n", regs.t1);
564 printf("\tt2=%-16lx\n", regs.t2);
565 printf("\tt3=%-16lx\n", regs.t3);
566 printf("\tt4=%-16lx\n", regs.t4);
567 printf("\tt5=%-16lx\n", regs.t5);
568 printf("\tt6=%-16lx\n", regs.t6);
569 printf("\tt7=%-16lx\n", regs.t7);
570#endif /* _MIPS_SIM == _ABIO32 */
571 printf("\ts0=%-16lx\n", regs.s0);
572 printf("\ts1=%-16lx\n", regs.s1);
573 printf("\ts2=%-16lx\n", regs.s2);
574 printf("\ts3=%-16lx\n", regs.s3);
575 printf("\ts4=%-16lx\n", regs.s4);
576 printf("\ts5=%-16lx\n", regs.s5);
577 printf("\ts6=%-16lx\n", regs.s6);
578 printf("\ts7=%-16lx\n", regs.s7);
579 printf("\tt8=%-16lx\n", regs.t8);
580 printf("\tt9=%-16lx\n", regs.t9);
581 printf("\tk0=%-16lx\n", regs.k0);
582 printf("\tk1=%-16lx\n", regs.k1);
583 printf("\tgp=%-16lx\n", regs.gp);
584 printf("\tsp=%-16lx\n", regs.sp);
585 printf("\tfp=%-16lx\n", regs.fp);
586 printf("\tra=%-16lx\n", regs.ra);
587
588 /* Saved special registers. */
589 printf("\tlo=%-16lx\n", regs.lo);
590 printf("\thi=%-16lx\n", regs.hi);
591 printf("\tpc=%-16lx\n", regs.pc);
592 printf("\tbadvaddr=%-16lx\n", regs.cp0_badvaddr);
593 printf("\tstatus=%-16lx\n", regs.cp0_status);
594 printf("\tcause=%-16lx\n", regs.cp0_cause);
595#elif defined(__sw_64)
596 printf("\tgp=%-16lx\n", regs.gp);
597 printf("\tsp=%-16lx\n", regs.sp);
598 printf("\tfp=%-16lx\n", regs.s6);
599 printf("\tra=%-16lx\n", regs.ra);
600 printf("\tpc=%-16lx\n", regs.pc);
601 printf("\tt12=%-16lx\n", regs.t12);
602
603 printf("\tv0=%-16lx\n", regs.v0);
604 printf("\ta0=%-16lx\n", regs.a0);
605 printf("\ta1=%-16lx\n", regs.a1);
606 printf("\ta2=%-16lx\n", regs.a2);
607 printf("\ta3=%-16lx\n", regs.a3);
608 printf("\ta4=%-16lx\n", regs.a4);
609 printf("\ta5=%-16lx\n", regs.a5);
610#elif defined(__aarch64__)
611 printf("\tsp=%-16lx\n", regs.sp);
612 printf("\tpc=%-16lx\n", regs.pc);
613
614 printf("\tx0=%-16lx\n", regs.x0);
615 printf("\tx1=%-16lx\n", regs.x1);
616 printf("\tx2=%-16lx\n", regs.x2);
617 printf("\tx3=%-16lx\n", regs.x3);
618 printf("\tx4=%-16lx\n", regs.x4);
619 printf("\tx5=%-16lx\n", regs.x5);
620#else
621#error unspport get_cpu_context
622#endif
623
624 if (out) {
625 memcpy(out, &regs, sizeof(regs));
626 }
627
628 return 0;
629}
630
631#if defined(__i386__) || defined(__x86_64__)
632#define BREAKPOINT_INSTRUCTION 0xcc
633#define BREAKPOINT_SIZE 1
634#elif defined(__mips__)
635#define BREAKPOINT_INSTRUCTION 0x0000000d
636#define BREAKPOINT_SIZE 4
637#elif defined(__sw_64)
638#define BREAKPOINT_INSTRUCTION 0x00000080
639#define BREAKPOINT_SIZE 4
640#elif defined(__aarch64__)
641#define BREAKPOINT_INSTRUCTION 0xd4200000
642#define BREAKPOINT_SIZE 4
643#else
644#error need implement in new arch
645#endif
646
647int gdb_break(int tid, uintptr_t addr, uint32_t* value)
648{
649 uint32_t ret;
650 uint32_t cc = BREAKPOINT_INSTRUCTION;
651 if (read_mem(tid, addr, &ret, BREAKPOINT_SIZE) != BREAKPOINT_SIZE) {
652 return -1;
653 }
654 if (write_mem(tid, addr, &cc, BREAKPOINT_SIZE) != BREAKPOINT_SIZE) {
655 return -2;
656 }
657
658 if (value) *value = ret;
659
660 return 0;
661}
662
663int gdb_delete(int tid, uintptr_t addr, uint32_t old_value)
664{
665 return write_mem(tid, addr, &old_value, BREAKPOINT_SIZE);
666}
667
668// gdb_print(pid, base, "/usr/lib/x86_64-linux-gnu/ld-2.24.so", addr, "struct link_map");
669int gdb_print(int pid, uintptr_t module_base, const char* filename,
670 uintptr_t var_address, const char* type_name)
671{
672 (void)pid;
673 (void)module_base;
674 (void)filename;
675 (void)var_address;
676 (void)type_name;
677 SymbolFile helper(module_base, filename, true);
678 /*
679 http://www.dwarfstd.org/doc/Debugging%20using%20DWARF-2012.pdf
680
681 .debug_abbrev Abbreviations used in the .debug_info section
682 .debug_aranges A mapping between memory address and compilation
683 .debug_frame Call Frame Information
684 .debug_info The core DWARF data containing DWARF Information Entries (DIEs)
685 .debug_line Line Number Program
686 .debug_loc Location descriptions
687 .debug_macinfo Macro descriptions
688 .debug_pubnames A lookup table for global objects and functions
689 .debug_pubtypes A lookup table for global types
690 .debug_ranges Address ranges referenced by DIEs
691 .debug_str String table used by .debug_info
692 .debug_types Type descriptions
693
694 for (const auto& cu : helper.m_dwarf.compilation_units()) {
695 for (const auto& die : cu.root()) {
696 if (die.has(dwarf::DW_AT::name) && at_name(die) == type_name) {
697 }
698 }
699 }
700 */
701
702 return 0;
703}
704