From a5bd75aab861df8cea8d1c6b88e764ad4a2c09ea Mon Sep 17 00:00:00 2001 From: Anatoly Trosinenko Date: Mon, 22 Jun 2020 13:14:02 +0300 Subject: [PATCH] [MSP430] Enable some basic support for debug information This commit technically permits LLVM to emit the debug information for ELF files for MSP430 architecture. Aside from this, it only defines the register numbers as defined by part 10.1 of MSP430 EABI specification (assuming the 1-byte subregisters share the register numbers with corresponding full-size registers). This commit was basically tested by me with TI-provided GCC 8.3.1 toolchain by compiling an example program with `clang` (please note manual linking may be required due to upstream `clang` not yet handling the `-msim` option necessary to run binaries on the GDB-provided simulator) and then running it and single-stepping with `msp430-elf-gdb` like this: ``` $sysroot/bin/msp430-elf-gdb ./test -ex "target sim" -ex "load ./test" (gdb) ... traditional GDB commands follow ... ``` While this implementation is most probably far from completeness and is considered experimental, it can already help with debugging MSP430 programs as well as finding issues in LLVM debug info support for MSP430 itself. One of the use cases includes trying to find a point where UBSan check in a trap-on-error mode was triggered. The expected debug information format is described in the [MSP430 Embedded Application Binary Interface](http://www.ti.com/lit/an/slaa534/slaa534.pdf) specification, part 10. Differential Revision: https://reviews.llvm.org/D81488 --- llvm/lib/Object/RelocationResolver.cpp | 23 ++++ .../Target/MSP430/MCTargetDesc/MSP430MCAsmInfo.cpp | 2 + llvm/lib/Target/MSP430/MSP430RegisterInfo.td | 2 + llvm/test/DebugInfo/MSP430/dwarf-basics.ll | 136 +++++++++++++++++++++ 4 files changed, 163 insertions(+) create mode 100644 llvm/test/DebugInfo/MSP430/dwarf-basics.ll diff --git a/llvm/lib/Object/RelocationResolver.cpp b/llvm/lib/Object/RelocationResolver.cpp index d45da76280d..3f3f79b0f4f 100644 --- a/llvm/lib/Object/RelocationResolver.cpp +++ b/llvm/lib/Object/RelocationResolver.cpp @@ -127,6 +127,27 @@ static uint64_t resolveMips64(RelocationRef R, uint64_t S, uint64_t A) { } } +static bool supportsMSP430(uint64_t Type) { + switch (Type) { + case ELF::R_MSP430_32: + case ELF::R_MSP430_16_BYTE: + return true; + default: + return false; + } +} + +static uint64_t resolveMSP430(RelocationRef R, uint64_t S, uint64_t A) { + switch (R.getType()) { + case ELF::R_MSP430_32: + return (S + getELFAddend(R)) & 0xFFFFFFFF; + case ELF::R_MSP430_16_BYTE: + return (S + getELFAddend(R)) & 0xFFFF; + default: + llvm_unreachable("Invalid relocation type"); + } +} + static bool supportsPPC64(uint64_t Type) { switch (Type) { case ELF::R_PPC64_ADDR32: @@ -614,6 +635,8 @@ getRelocationResolver(const ObjectFile &Obj) { case Triple::mipsel: case Triple::mips: return {supportsMips32, resolveMips32}; + case Triple::msp430: + return {supportsMSP430, resolveMSP430}; case Triple::sparc: return {supportsSparc32, resolveSparc32}; case Triple::hexagon: diff --git a/llvm/lib/Target/MSP430/MCTargetDesc/MSP430MCAsmInfo.cpp b/llvm/lib/Target/MSP430/MCTargetDesc/MSP430MCAsmInfo.cpp index 6117567dcae..de07b47096d 100644 --- a/llvm/lib/Target/MSP430/MCTargetDesc/MSP430MCAsmInfo.cpp +++ b/llvm/lib/Target/MSP430/MCTargetDesc/MSP430MCAsmInfo.cpp @@ -24,4 +24,6 @@ MSP430MCAsmInfo::MSP430MCAsmInfo(const Triple &TT, AlignmentIsInBytes = false; UsesELFSectionDirectiveForBSS = true; + + SupportsDebugInformation = true; } diff --git a/llvm/lib/Target/MSP430/MSP430RegisterInfo.td b/llvm/lib/Target/MSP430/MSP430RegisterInfo.td index 11003dba383..0ba8e1c7ebb 100644 --- a/llvm/lib/Target/MSP430/MSP430RegisterInfo.td +++ b/llvm/lib/Target/MSP430/MSP430RegisterInfo.td @@ -15,6 +15,7 @@ class MSP430Reg num, string n, list alt = []> : Register { let Namespace = "MSP430"; let HWEncoding{3-0} = num; let AltNames = alt; + let DwarfNumbers = [num]; } class MSP430RegWithSubregs num, string n, list subregs, @@ -24,6 +25,7 @@ class MSP430RegWithSubregs num, string n, list subregs, let Namespace = "MSP430"; let HWEncoding{3-0} = num; let AltNames = alt; + let DwarfNumbers = [num]; } //===----------------------------------------------------------------------===// diff --git a/llvm/test/DebugInfo/MSP430/dwarf-basics.ll b/llvm/test/DebugInfo/MSP430/dwarf-basics.ll new file mode 100644 index 00000000000..be875a672c0 --- /dev/null +++ b/llvm/test/DebugInfo/MSP430/dwarf-basics.ll @@ -0,0 +1,136 @@ +; RUN: llc --filetype=obj -o %t < %s +; RUN: llvm-dwarfdump --debug-info %t | FileCheck %s +; RUN: llvm-dwarfdump --verify %t + +; This file was based on output of +; +; clang -target msp430 -S -emit-llvm -gdwarf-3 -Os dwarf-basics.c +; +; for the following dwarf-basics.c +; +; struct X { +; void *a; +; }; +; +; int f(long y, struct X *p) +; { +; return 42; +; } +; + +; CHECK: file format elf32-msp430 + +; CHECK: .debug_info contents: +; CHECK: Compile Unit: length = 0x{{.*}}, format = DWARF32, version = 0x0003, abbr_offset = 0x0000, addr_size = 0x02 (next unit at 0x{{.*}}) + +; CHECK: DW_TAG_compile_unit +; CHECK: DW_AT_producer ("clang version 11.0.0 (git@...)") +; CHECK: DW_AT_language (DW_LANG_C99) +; CHECK: DW_AT_name ("dwarf-basics.c") +; CHECK: DW_AT_stmt_list (0x{{.*}}) +; CHECK: DW_AT_comp_dir ("/tmp") +; CHECK: DW_AT_low_pc (0x{{.*}}) +; CHECK: DW_AT_high_pc (0x{{.*}}) + +; CHECK: DW_TAG_subprogram +; CHECK: DW_AT_low_pc (0x{{.*}}) +; CHECK: DW_AT_high_pc (0x{{.*}}) +; CHECK: DW_AT_frame_base (DW_OP_reg1 SPB) +; CHECK: DW_AT_name ("f") +; CHECK: DW_AT_decl_file ("/tmp/dwarf-basics.c") +; CHECK: DW_AT_decl_line (5) +; CHECK: DW_AT_prototyped (0x01) +; CHECK: DW_AT_type (0x{{.*}} "int") +; CHECK: DW_AT_external (0x01) + +; CHECK: DW_TAG_formal_parameter +; CHECK: DW_AT_location (0x{{.*}}: +; CHECK: [0x0000, 0x0004): DW_OP_reg12 R12B) +; CHECK: DW_AT_name ("y") +; CHECK: DW_AT_decl_file ("/tmp/dwarf-basics.c") +; CHECK: DW_AT_decl_line (5) +; CHECK: DW_AT_type (0x{{.*}} "long int") + +; CHECK: DW_TAG_formal_parameter +; CHECK: DW_AT_location (DW_OP_reg14 R14B) +; CHECK: DW_AT_name ("p") +; CHECK: DW_AT_decl_file ("/tmp/dwarf-basics.c") +; CHECK: DW_AT_decl_line (5) +; CHECK: DW_AT_type (0x{{.*}} "X*") + +; CHECK: NULL + +; CHECK: DW_TAG_base_type +; CHECK: DW_AT_name ("int") +; CHECK: DW_AT_encoding (DW_ATE_signed) +; CHECK: DW_AT_byte_size (0x02) + +; CHECK: DW_TAG_base_type +; CHECK: DW_AT_name ("long int") +; CHECK: DW_AT_encoding (DW_ATE_signed) +; CHECK: DW_AT_byte_size (0x04) + +; CHECK: DW_TAG_pointer_type +; CHECK: DW_AT_type (0x{{.*}} "X") + +; CHECK: DW_TAG_structure_type +; CHECK: DW_AT_name ("X") +; CHECK: DW_AT_byte_size (0x02) +; CHECK: DW_AT_decl_file ("/tmp/dwarf-basics.c") +; CHECK: DW_AT_decl_line (1) + +; CHECK: DW_TAG_member +; CHECK: DW_AT_name ("a") +; CHECK: DW_AT_type (0x{{.*}} "*") +; CHECK: DW_AT_decl_file ("/tmp/dwarf-basics.c") +; CHECK: DW_AT_decl_line (2) +; CHECK: DW_AT_data_member_location (0x00) + +; CHECK: NULL + +; CHECK: DW_TAG_pointer_type + +; CHECK: NULL + + +source_filename = "dwarf-basics.c" +target datalayout = "e-m:e-p:16:16-i32:16-i64:16-f32:16-f64:16-a:8-n8:16-S16" +target triple = "msp430" + +%struct.X = type { i8* } + +define i16 @f(i32 %y, %struct.X* %p) !dbg !7 { +entry: + call void @llvm.dbg.value(metadata i32 %y, metadata !18, metadata !DIExpression()), !dbg !20 + call void @llvm.dbg.value(metadata %struct.X* %p, metadata !19, metadata !DIExpression()), !dbg !20 + ret i16 42, !dbg !21 +} + +declare void @llvm.dbg.value(metadata, metadata, metadata) + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 11.0.0 (git@...)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "dwarf-basics.c", directory: "/tmp") +!2 = !{} +!3 = !{i32 7, !"Dwarf Version", i32 3} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 2} +!6 = !{!"clang version 11.0.0 (git@...)"} +!7 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 5, type: !8, scopeLine: 6, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !17) +!8 = !DISubroutineType(types: !9) +!9 = !{!10, !11, !12} +!10 = !DIBasicType(name: "int", size: 16, encoding: DW_ATE_signed) +!11 = !DIBasicType(name: "long int", size: 32, encoding: DW_ATE_signed) +!12 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !13, size: 16) +!13 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "X", file: !1, line: 1, size: 16, elements: !14) +!14 = !{!15} +!15 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !13, file: !1, line: 2, baseType: !16, size: 16) +!16 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 16) +!17 = !{!18, !19} +!18 = !DILocalVariable(name: "y", arg: 1, scope: !7, file: !1, line: 5, type: !11) +!19 = !DILocalVariable(name: "p", arg: 2, scope: !7, file: !1, line: 5, type: !12) +!20 = !DILocation(line: 0, scope: !7) +!21 = !DILocation(line: 7, column: 3, scope: !7) -- 2.11.0