[llvm] dc4a6f5 - [llvm-objdump] Display locations of variables alongside disassembly

Oliver Stannard via llvm-commits llvm-commits at lists.llvm.org
Thu Jul 9 01:58:18 PDT 2020


Author: Oliver Stannard
Date: 2020-07-09T09:58:00+01:00
New Revision: dc4a6f5db4f0178bae43ef615cc8902c759d6195

URL: https://github.com/llvm/llvm-project/commit/dc4a6f5db4f0178bae43ef615cc8902c759d6195
DIFF: https://github.com/llvm/llvm-project/commit/dc4a6f5db4f0178bae43ef615cc8902c759d6195.diff

LOG: [llvm-objdump] Display locations of variables alongside disassembly

This adds the --debug-vars option to llvm-objdump, which prints
locations (registers/memory) of source-level variables alongside the
disassembly based on DWARF info. A vertical line is printed for each
live-range, with a label at the top giving the variable name and
location, and the position and length of the line indicating the program
counter range in which it is valid.

Differential revision: https://reviews.llvm.org/D70720

Added: 
    llvm/test/tools/llvm-objdump/ARM/Inputs/debug.c
    llvm/test/tools/llvm-objdump/ARM/Inputs/wide-char.c
    llvm/test/tools/llvm-objdump/ARM/debug-vars-dwarf4-sections.s
    llvm/test/tools/llvm-objdump/ARM/debug-vars-dwarf4.s
    llvm/test/tools/llvm-objdump/ARM/debug-vars-dwarf5-sections.s
    llvm/test/tools/llvm-objdump/ARM/debug-vars-dwarf5.s
    llvm/test/tools/llvm-objdump/ARM/debug-vars-wide-chars.s
    llvm/test/tools/llvm-objdump/PowerPC/debug-vars.s

Modified: 
    llvm/docs/CommandGuide/llvm-objdump.rst
    llvm/include/llvm/DebugInfo/DWARF/DWARFExpression.h
    llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp
    llvm/tools/llvm-objdump/llvm-objdump.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/docs/CommandGuide/llvm-objdump.rst b/llvm/docs/CommandGuide/llvm-objdump.rst
index 2de48d66536f..df4cf746abbb 100644
--- a/llvm/docs/CommandGuide/llvm-objdump.rst
+++ b/llvm/docs/CommandGuide/llvm-objdump.rst
@@ -123,6 +123,17 @@ OPTIONS
 
   Demangle symbol names in the output.
 
+.. option:: --debug-vars=<format>
+
+  Print the locations (in registers or memory) of source-level variables
+  alongside disassembly. ``format`` may be ``unicode`` or ``ascii``, defaulting
+  to ``unicode`` if omitted.
+
+.. option:: --debug-vars-indent=<width>
+
+  Distance to indent the source-level variable display, relative to the start
+  of the disassembly. Defaults to 40 characters.
+
 .. option:: -j, --section=<section1[,section2,...]>
 
   Perform commands on the specified sections only. For Mach-O use

diff  --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFExpression.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFExpression.h
index 28929306ca92..1aff2624990f 100644
--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFExpression.h
+++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFExpression.h
@@ -142,6 +142,12 @@ class DWARFExpression {
   void print(raw_ostream &OS, const MCRegisterInfo *RegInfo, DWARFUnit *U,
              bool IsEH = false) const;
 
+  /// Print the expression in a format intended to be compact and useful to a
+  /// user, but not perfectly unambiguous, or capable of representing every
+  /// valid DWARF expression. Returns true if the expression was sucessfully
+  /// printed.
+  bool printCompact(raw_ostream &OS, const MCRegisterInfo &RegInfo);
+
   bool verify(DWARFUnit *U);
 
 private:

diff  --git a/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp b/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp
index 28b24b3baaab..d3c1cd5bb88f 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp
@@ -374,4 +374,74 @@ bool DWARFExpression::verify(DWARFUnit *U) {
   return true;
 }
 
+/// A user-facing string representation of a DWARF expression. This might be an
+/// Address expression, in which case it will be implicitly dereferenced, or a
+/// Value expression.
+struct PrintedExpr {
+  enum ExprKind {
+    Address,
+    Value,
+  };
+  ExprKind Kind;
+  SmallString<16> String;
+
+  PrintedExpr(ExprKind K = Address) : Kind(K) {}
+};
+
+static bool printCompactDWARFExpr(raw_ostream &OS, DWARFExpression::iterator I,
+                                  const DWARFExpression::iterator E,
+                                  const MCRegisterInfo &MRI) {
+  SmallVector<PrintedExpr, 4> Stack;
+
+  while (I != E) {
+    DWARFExpression::Operation &Op = *I;
+    uint8_t Opcode = Op.getCode();
+    switch (Opcode) {
+    case dwarf::DW_OP_regx: {
+      // DW_OP_regx: A register, with the register num given as an operand.
+      // Printed as the plain register name.
+      uint64_t DwarfRegNum = Op.getRawOperand(0);
+      Optional<unsigned> LLVMRegNum = MRI.getLLVMRegNum(DwarfRegNum, false);
+      if (!LLVMRegNum) {
+        OS << "<unknown register " << DwarfRegNum << ">";
+        return false;
+      }
+      raw_svector_ostream S(Stack.emplace_back(PrintedExpr::Value).String);
+      S << MRI.getName(*LLVMRegNum);
+      break;
+    }
+    default:
+      if (Opcode >= dwarf::DW_OP_reg0 && Opcode <= dwarf::DW_OP_reg31) {
+        // DW_OP_reg<N>: A register, with the register num implied by the
+        // opcode. Printed as the plain register name.
+        uint64_t DwarfRegNum = Opcode - dwarf::DW_OP_reg0;
+        Optional<unsigned> LLVMRegNum = MRI.getLLVMRegNum(DwarfRegNum, false);
+        if (!LLVMRegNum) {
+          OS << "<unknown register " << DwarfRegNum << ">";
+          return false;
+        }
+        raw_svector_ostream S(Stack.emplace_back(PrintedExpr::Value).String);
+        S << MRI.getName(*LLVMRegNum);
+      } else {
+        // If we hit an unknown operand, we don't know its effect on the stack,
+        // so bail out on the whole expression.
+        OS << "<unknown op " << dwarf::OperationEncodingString(Opcode) << " ("
+           << (int)Opcode << ")>";
+        return false;
+      }
+      break;
+    }
+    ++I;
+  }
+
+  assert(Stack.size() == 1 && "expected one value on stack");
+  OS << Stack.front().String;
+
+  return true;
+}
+
+bool DWARFExpression::printCompact(raw_ostream &OS, const MCRegisterInfo &MRI) {
+  return printCompactDWARFExpr(OS, begin(), end(), MRI);
+}
+
 } // namespace llvm

diff  --git a/llvm/test/tools/llvm-objdump/ARM/Inputs/debug.c b/llvm/test/tools/llvm-objdump/ARM/Inputs/debug.c
new file mode 100644
index 000000000000..20c17f7d9762
--- /dev/null
+++ b/llvm/test/tools/llvm-objdump/ARM/Inputs/debug.c
@@ -0,0 +1,10 @@
+int foo(int a, int b, int c) {
+  int x = a + b;
+  int y = x + c;
+  return y;
+}
+
+int bar(int a) {
+  a++;
+  return a;
+}

diff  --git a/llvm/test/tools/llvm-objdump/ARM/Inputs/wide-char.c b/llvm/test/tools/llvm-objdump/ARM/Inputs/wide-char.c
new file mode 100644
index 000000000000..8d923be01328
--- /dev/null
+++ b/llvm/test/tools/llvm-objdump/ARM/Inputs/wide-char.c
@@ -0,0 +1,3 @@
+int foo(int *喵) {
+  return *喵;
+}

diff  --git a/llvm/test/tools/llvm-objdump/ARM/debug-vars-dwarf4-sections.s b/llvm/test/tools/llvm-objdump/ARM/debug-vars-dwarf4-sections.s
new file mode 100644
index 000000000000..9bbb36f14e3a
--- /dev/null
+++ b/llvm/test/tools/llvm-objdump/ARM/debug-vars-dwarf4-sections.s
@@ -0,0 +1,351 @@
+## Check that the --debug-vars option works for simple register locations, when
+## using DWARF4 debug info, with functions in multiple sections.
+
+## Generated with this compile command, with the source code in Inputs/debug.c:
+## clang --target=arm--none-eabi -march=armv7-a -c debug.c -O1 -gdwarf-4 -S -o - -ffunction-sections
+
+# RUN: llvm-mc -triple armv8a--none-eabi < %s -filetype=obj | \
+# RUN:     llvm-objdump - -d --debug-vars --no-show-raw-insn | \
+# RUN:     FileCheck %s
+
+# CHECK: Disassembly of section .text.foo:
+# CHECK-EMPTY:
+# CHECK-NEXT: 00000000 <foo>:
+# CHECK-NEXT:                                                                   ┠─ a = R0
+# CHECK-NEXT:                                                                   ┃ ┠─ b = R1
+# CHECK-NEXT:                                                                   ┃ ┃ ┠─ c = R2
+# CHECK-NEXT:                                                                   ┃ ┃ ┃ ┌─ x = R0
+# CHECK-NEXT:        0:       add     r0, r1, r0                                ┻ ┃ ┃ ╈
+# CHECK-NEXT:                                                                   ┌─ y = R0
+# CHECK-NEXT:        4:       add     r0, r0, r2                                ╈ ┃ ┃ ┻
+# CHECK-NEXT:        8:       bx      lr                                        ┻ ┻ ┻
+# CHECK-EMPTY:
+# CHECK-NEXT: Disassembly of section .text.bar:
+# CHECK-EMPTY:
+# CHECK-NEXT: 00000000 <bar>:
+# CHECK-NEXT:                                                                   ┠─ a = R0
+# CHECK-NEXT:        0:       add     r0, r0, #1                                ┃
+# CHECK-NEXT:        4:       bx      lr                                        ┻
+
+	.text
+	.syntax unified
+	.eabi_attribute	67, "2.09"
+	.eabi_attribute	6, 10
+	.eabi_attribute	7, 65
+	.eabi_attribute	8, 1
+	.eabi_attribute	9, 2
+	.fpu	neon
+	.eabi_attribute	34, 0
+	.eabi_attribute	17, 1
+	.eabi_attribute	20, 1
+	.eabi_attribute	21, 1
+	.eabi_attribute	23, 3
+	.eabi_attribute	24, 1
+	.eabi_attribute	25, 1
+	.eabi_attribute	38, 1
+	.eabi_attribute	18, 4
+	.eabi_attribute	26, 2
+	.eabi_attribute	14, 0
+	.file	"debug.c"
+	.section	.text.foo,"ax",%progbits
+	.globl	foo
+	.p2align	2
+	.type	foo,%function
+	.code	32
+foo:
+.Lfunc_begin0:
+	.file	1 "/work" "llvm/src/llvm/test/tools/llvm-objdump/ARM/Inputs/debug.c"
+	.loc	1 1 0
+	.fnstart
+	.cfi_sections .debug_frame
+	.cfi_startproc
+	.loc	1 2 13 prologue_end
+	add	r0, r1, r0
+.Ltmp0:
+	.loc	1 3 13
+	add	r0, r0, r2
+.Ltmp1:
+	.loc	1 4 3
+	bx	lr
+.Ltmp2:
+.Lfunc_end0:
+	.size	foo, .Lfunc_end0-foo
+	.cfi_endproc
+	.cantunwind
+	.fnend
+
+	.section	.text.bar,"ax",%progbits
+	.globl	bar
+	.p2align	2
+	.type	bar,%function
+	.code	32
+bar:
+.Lfunc_begin1:
+	.loc	1 7 0
+	.fnstart
+	.cfi_startproc
+	.loc	1 8 4 prologue_end
+	add	r0, r0, #1
+.Ltmp3:
+	.loc	1 9 3
+	bx	lr
+.Ltmp4:
+.Lfunc_end1:
+	.size	bar, .Lfunc_end1-bar
+	.cfi_endproc
+	.cantunwind
+	.fnend
+
+	.section	.debug_str,"MS",%progbits,1
+.Linfo_string0:
+	.asciz	"clang version 10.0.0 (git at github.com:llvm/llvm-project.git e73f78acd34360f7450b81167d9dc858ccddc262)"
+.Linfo_string1:
+	.asciz	"/work/llvm/src/llvm/test/tools/llvm-objdump/ARM/Inputs/debug.c"
+.Linfo_string2:
+	.asciz	"/work/scratch"
+.Linfo_string3:
+	.asciz	"foo"
+.Linfo_string4:
+	.asciz	"int"
+.Linfo_string5:
+	.asciz	"bar"
+.Linfo_string6:
+	.asciz	"a"
+.Linfo_string7:
+	.asciz	"b"
+.Linfo_string8:
+	.asciz	"c"
+.Linfo_string9:
+	.asciz	"x"
+.Linfo_string10:
+	.asciz	"y"
+	.section	.debug_loc,"",%progbits
+.Ldebug_loc0:
+	.long	-1
+	.long	.Lfunc_begin0
+	.long	.Lfunc_begin0-.Lfunc_begin0
+	.long	.Ltmp0-.Lfunc_begin0
+	.short	1
+	.byte	80
+	.long	0
+	.long	0
+.Ldebug_loc1:
+	.long	-1
+	.long	.Lfunc_begin0
+	.long	.Ltmp0-.Lfunc_begin0
+	.long	.Ltmp1-.Lfunc_begin0
+	.short	1
+	.byte	80
+	.long	0
+	.long	0
+.Ldebug_loc2:
+	.long	-1
+	.long	.Lfunc_begin0
+	.long	.Ltmp1-.Lfunc_begin0
+	.long	.Lfunc_end0-.Lfunc_begin0
+	.short	1
+	.byte	80
+	.long	0
+	.long	0
+	.section	.debug_abbrev,"",%progbits
+	.byte	1
+	.byte	17
+	.byte	1
+	.byte	37
+	.byte	14
+	.byte	19
+	.byte	5
+	.byte	3
+	.byte	14
+	.byte	16
+	.byte	23
+	.byte	27
+	.byte	14
+	.byte	17
+	.byte	1
+	.byte	85
+	.byte	23
+	.byte	0
+	.byte	0
+	.byte	2
+	.byte	46
+	.byte	1
+	.byte	17
+	.byte	1
+	.byte	18
+	.byte	6
+	.byte	64
+	.byte	24
+	.ascii	"\227B"
+	.byte	25
+	.byte	3
+	.byte	14
+	.byte	58
+	.byte	11
+	.byte	59
+	.byte	11
+	.byte	39
+	.byte	25
+	.byte	73
+	.byte	19
+	.byte	63
+	.byte	25
+	.byte	0
+	.byte	0
+	.byte	3
+	.byte	5
+	.byte	0
+	.byte	2
+	.byte	23
+	.byte	3
+	.byte	14
+	.byte	58
+	.byte	11
+	.byte	59
+	.byte	11
+	.byte	73
+	.byte	19
+	.byte	0
+	.byte	0
+	.byte	4
+	.byte	5
+	.byte	0
+	.byte	2
+	.byte	24
+	.byte	3
+	.byte	14
+	.byte	58
+	.byte	11
+	.byte	59
+	.byte	11
+	.byte	73
+	.byte	19
+	.byte	0
+	.byte	0
+	.byte	5
+	.byte	52
+	.byte	0
+	.byte	2
+	.byte	23
+	.byte	3
+	.byte	14
+	.byte	58
+	.byte	11
+	.byte	59
+	.byte	11
+	.byte	73
+	.byte	19
+	.byte	0
+	.byte	0
+	.byte	6
+	.byte	36
+	.byte	0
+	.byte	3
+	.byte	14
+	.byte	62
+	.byte	11
+	.byte	11
+	.byte	11
+	.byte	0
+	.byte	0
+	.byte	0
+	.section	.debug_info,"",%progbits
+.Lcu_begin0:
+	.long	.Ldebug_info_end0-.Ldebug_info_start0
+.Ldebug_info_start0:
+	.short	4
+	.long	.debug_abbrev
+	.byte	4
+	.byte	1
+	.long	.Linfo_string0
+	.short	12
+	.long	.Linfo_string1
+	.long	.Lline_table_start0
+	.long	.Linfo_string2
+	.long	0
+	.long	.Ldebug_ranges0
+	.byte	2
+	.long	.Lfunc_begin0
+	.long	.Lfunc_end0-.Lfunc_begin0
+	.byte	1
+	.byte	91
+
+	.long	.Linfo_string3
+	.byte	1
+	.byte	1
+
+	.long	166
+
+	.byte	3
+	.long	.Ldebug_loc0
+	.long	.Linfo_string6
+	.byte	1
+	.byte	1
+	.long	166
+	.byte	4
+	.byte	1
+	.byte	81
+	.long	.Linfo_string7
+	.byte	1
+	.byte	1
+	.long	166
+	.byte	4
+	.byte	1
+	.byte	82
+	.long	.Linfo_string8
+	.byte	1
+	.byte	1
+	.long	166
+	.byte	5
+	.long	.Ldebug_loc1
+	.long	.Linfo_string9
+	.byte	1
+	.byte	2
+	.long	166
+	.byte	5
+	.long	.Ldebug_loc2
+	.long	.Linfo_string10
+	.byte	1
+	.byte	3
+	.long	166
+	.byte	0
+	.byte	2
+	.long	.Lfunc_begin1
+	.long	.Lfunc_end1-.Lfunc_begin1
+	.byte	1
+	.byte	91
+
+	.long	.Linfo_string5
+	.byte	1
+	.byte	7
+
+	.long	166
+
+	.byte	4
+	.byte	1
+	.byte	80
+	.long	.Linfo_string6
+	.byte	1
+	.byte	7
+	.long	166
+	.byte	0
+	.byte	6
+	.long	.Linfo_string4
+	.byte	5
+	.byte	4
+	.byte	0
+.Ldebug_info_end0:
+	.section	.debug_ranges,"",%progbits
+.Ldebug_ranges0:
+	.long	.Lfunc_begin0
+	.long	.Lfunc_end0
+	.long	.Lfunc_begin1
+	.long	.Lfunc_end1
+	.long	0
+	.long	0
+	.ident	"clang version 10.0.0 (git at github.com:llvm/llvm-project.git e73f78acd34360f7450b81167d9dc858ccddc262)"
+	.section	".note.GNU-stack","",%progbits
+	.addrsig
+	.eabi_attribute	30, 1
+	.section	.debug_line,"",%progbits
+.Lline_table_start0:

diff  --git a/llvm/test/tools/llvm-objdump/ARM/debug-vars-dwarf4.s b/llvm/test/tools/llvm-objdump/ARM/debug-vars-dwarf4.s
new file mode 100644
index 000000000000..bf0c7bd52feb
--- /dev/null
+++ b/llvm/test/tools/llvm-objdump/ARM/debug-vars-dwarf4.s
@@ -0,0 +1,454 @@
+## Check that the --debug-vars option works for simple register locations, when
+## using DWARF4 debug info, with multiple functions in one section. Check that
+## the live-range lines are rendered correctly when using the --no-show-raw-insn,
+## --line-numbers and --source options. These do not affect the DWARF parsing
+## used by --debug-vars, but do add extra lines or columns to the output, so we
+## test to make sure the live ranges are still displayed correctly.
+
+## Generated with this compile command, with the source code in Inputs/debug.c:
+## clang --target=arm--none-eabi -march=armv7-a -c debug.c -O1 -gdwarf-4 -S -o -
+
+# RUN: llvm-mc -triple armv8a--none-eabi < %s -filetype=obj | \
+# RUN:     llvm-objdump - -d --debug-vars | \
+# RUN:     FileCheck %s --check-prefix=RAW --strict-whitespace
+
+## Check that passing the default value for --debug-vars-indent (40) makes no
+## change to the output.
+# RUN: llvm-mc -triple armv8a--none-eabi < %s -filetype=obj | \
+# RUN:     llvm-objdump - -d --debug-vars --debug-vars-indent=40 | \
+# RUN:     FileCheck %s --check-prefix=RAW --strict-whitespace
+
+# RUN: llvm-mc -triple armv8a--none-eabi < %s -filetype=obj | \
+# RUN:     llvm-objdump - -d --debug-vars --debug-vars-indent=30 | \
+# RUN:     FileCheck %s --check-prefix=INDENT --strict-whitespace
+
+# RUN: llvm-mc -triple armv8a--none-eabi < %s -filetype=obj | \
+# RUN:     llvm-objdump - -d --debug-vars --no-show-raw-insn | \
+# RUN:     FileCheck %s --check-prefix=NO-RAW --strict-whitespace
+
+# RUN: llvm-mc -triple armv8a--none-eabi < %s -filetype=obj | \
+# RUN:     llvm-objdump - -d --debug-vars --no-show-raw-insn --line-numbers | \
+# RUN:     FileCheck %s --check-prefix=LINE-NUMS --strict-whitespace
+
+# RUN: mkdir -p %t/a
+# RUN: cp %p/Inputs/debug.c %t/a/debug.c
+# RUN: sed -e "s,SRC_COMPDIR,%/t/a,g" %s > %t.s
+# RUN: llvm-mc -triple armv8a--none-eabi < %t.s -filetype=obj | \
+# RUN:     llvm-objdump - -d --debug-vars --no-show-raw-insn --source | \
+# RUN:     FileCheck %s --check-prefix=SOURCE --strict-whitespace
+
+## An optional argument to the --debug-vars= option can be used to switch
+## between unicode and ascii output (with unicode being the default).
+# RUN: llvm-mc -triple armv8a--none-eabi < %s -filetype=obj | \
+# RUN:     llvm-objdump - -d --debug-vars=unicode | \
+# RUN:     FileCheck %s --check-prefix=RAW --strict-whitespace
+# RUN: llvm-mc -triple armv8a--none-eabi < %s -filetype=obj | \
+# RUN:     llvm-objdump - -d --debug-vars=ascii | \
+# RUN:     FileCheck %s --check-prefix=ASCII --strict-whitespace
+
+## Note that llvm-objdump emits tab characters in the disassembly, assuming an
+## 8-byte tab stop, so these might not look aligned in a text editor.
+
+# RAW: 00000000 <foo>:
+# RAW-NEXT:                                                                 ┠─ a = R0 
+# RAW-NEXT:                                                                 ┃ ┠─ b = R1 
+# RAW-NEXT:                                                                 ┃ ┃ ┠─ c = R2 
+# RAW-NEXT:                                                                 ┃ ┃ ┃ ┌─ x = R0 
+# RAW-NEXT:        0: 00 00 81 e0  	add	r0, r1, r0                      ┻ ┃ ┃ ╈   
+# RAW-NEXT:                                                                 ┌─ y = R0 
+# RAW-NEXT:        4: 02 00 80 e0  	add	r0, r0, r2                      ╈ ┃ ┃ ┻   
+# RAW-NEXT:        8: 1e ff 2f e1  	bx	lr                              ┻ ┻ ┻     
+# RAW-EMPTY:
+# RAW-NEXT: 0000000c <bar>:
+# RAW-NEXT:                                                                 ┠─ a = R0 
+# RAW-NEXT:        c: 01 00 80 e2  	add	r0, r0, #1                      ┃         
+# RAW-NEXT:       10: 1e ff 2f e1  	bx	lr                              ┻         
+
+
+# INDENT: 00000000 <foo>:
+# INDENT-NEXT:                                                       ┠─ a = R0 
+# INDENT-NEXT:                                                       ┃ ┠─ b = R1 
+# INDENT-NEXT:                                                       ┃ ┃ ┠─ c = R2 
+# INDENT-NEXT:                                                       ┃ ┃ ┃ ┌─ x = R0 
+# INDENT-NEXT:        0: 00 00 81 e0  	add	r0, r1, r0            ┻ ┃ ┃ ╈   
+# INDENT-NEXT:                                                       ┌─ y = R0 
+# INDENT-NEXT:        4: 02 00 80 e0  	add	r0, r0, r2            ╈ ┃ ┃ ┻   
+# INDENT-NEXT:        8: 1e ff 2f e1  	bx	lr                    ┻ ┻ ┻     
+# INDENT-EMPTY:
+# INDENT-NEXT: 0000000c <bar>:
+# INDENT-NEXT:                                                       ┠─ a = R0 
+# INDENT-NEXT:        c: 01 00 80 e2  	add	r0, r0, #1            ┃         
+# INDENT-NEXT:       10: 1e ff 2f e1  	bx	lr                    ┻         
+
+# NO-RAW: 00000000 <foo>:
+# NO-RAW-NEXT:                                                         ┠─ a = R0
+# NO-RAW-NEXT:                                                         ┃ ┠─ b = R1
+# NO-RAW-NEXT:                                                         ┃ ┃ ┠─ c = R2
+# NO-RAW-NEXT:                                                         ┃ ┃ ┃ ┌─ x = R0
+# NO-RAW-NEXT:        0:      	add	r0, r1, r0                      ┻ ┃ ┃ ╈
+# NO-RAW-NEXT:                                                         ┌─ y = R0
+# NO-RAW-NEXT:        4:      	add	r0, r0, r2                      ╈ ┃ ┃ ┻
+# NO-RAW-NEXT:        8:      	bx	lr                              ┻ ┻ ┻
+# NO-RAW-EMPTY:
+# NO-RAW-NEXT: 0000000c <bar>:
+# NO-RAW-NEXT:                                                         ┠─ a = R0
+# NO-RAW-NEXT:        c:      	add	r0, r0, #1                      ┃
+# NO-RAW-NEXT:       10:      	bx	lr                              ┻
+
+# LINE-NUMS: 00000000 <foo>:
+# LINE-NUMS-NEXT: ; foo():
+# LINE-NUMS-NEXT: ; SRC_COMPDIR{{[\\/]}}debug.c:2                                 ┠─ a = R0
+# LINE-NUMS-NEXT:                                                         ┃ ┠─ b = R1
+# LINE-NUMS-NEXT:                                                         ┃ ┃ ┠─ c = R2
+# LINE-NUMS-NEXT:                                                         ┃ ┃ ┃ ┌─ x = R0
+# LINE-NUMS-NEXT:        0:      	add	r0, r1, r0                      ┻ ┃ ┃ ╈
+# LINE-NUMS-NEXT: ; SRC_COMPDIR{{[\\/]}}debug.c:3                                 ┌─ y = R0
+# LINE-NUMS-NEXT:        4:      	add	r0, r0, r2                      ╈ ┃ ┃ ┻
+# LINE-NUMS-NEXT: ; SRC_COMPDIR{{[\\/]}}debug.c:4                                 ┃ ┃ ┃
+# LINE-NUMS-NEXT:        8:      	bx	lr                              ┻ ┻ ┻
+# LINE-NUMS-EMPTY:
+# LINE-NUMS-NEXT: 0000000c <bar>:
+# LINE-NUMS-NEXT: ; bar():
+# LINE-NUMS-NEXT: ; SRC_COMPDIR{{[\\/]}}debug.c:8                                 ┠─ a = R0
+# LINE-NUMS-NEXT:        c:      	add	r0, r0, #1                      ┃
+# LINE-NUMS-NEXT: ; SRC_COMPDIR{{[\\/]}}debug.c:9                                 ┃
+# LINE-NUMS-NEXT:       10:      	bx	lr                              ┻
+
+# SOURCE: 00000000 <foo>:
+# SOURCE-NEXT: ;   int x = a + b;                                      ┠─ a = R0
+# SOURCE-NEXT:                                                         ┃ ┠─ b = R1
+# SOURCE-NEXT:                                                         ┃ ┃ ┠─ c = R2
+# SOURCE-NEXT:                                                         ┃ ┃ ┃ ┌─ x = R0
+# SOURCE-NEXT:        0:      	add	r0, r1, r0                      ┻ ┃ ┃ ╈
+# SOURCE-NEXT: ;   int y = x + c;                                      ┌─ y = R0
+# SOURCE-NEXT:        4:      	add	r0, r0, r2                      ╈ ┃ ┃ ┻
+# SOURCE-NEXT: ;   return y;                                           ┃ ┃ ┃
+# SOURCE-NEXT:        8:      	bx	lr                              ┻ ┻ ┻
+# SOURCE-EMPTY:
+# SOURCE-NEXT: 0000000c <bar>:
+# SOURCE-NEXT: ;   a++;                                                ┠─ a = R0
+# SOURCE-NEXT:        c:      	add	r0, r0, #1                      ┃
+# SOURCE-NEXT: ;   return a;                                           ┃
+# SOURCE-NEXT:       10:      	bx	lr                              ┻
+
+# ASCII: 00000000 <foo>:
+# ASCII-NEXT:                                                                 |- a = R0 
+# ASCII-NEXT:                                                                 | |- b = R1 
+# ASCII-NEXT:                                                                 | | |- c = R2 
+# ASCII-NEXT:                                                                 | | | /- x = R0 
+# ASCII-NEXT:        0: 00 00 81 e0  	add	r0, r1, r0                      v | | ^   
+# ASCII-NEXT:                                                                 /- y = R0 
+# ASCII-NEXT:        4: 02 00 80 e0  	add	r0, r0, r2                      ^ | | v   
+# ASCII-NEXT:        8: 1e ff 2f e1  	bx	lr                              v v v     
+# ASCII-EMPTY:
+# ASCII-NEXT: 0000000c <bar>:
+# ASCII-NEXT:                                                                 |- a = R0 
+# ASCII-NEXT:        c: 01 00 80 e2  	add	r0, r0, #1                      |         
+# ASCII-NEXT:       10: 1e ff 2f e1  	bx	lr                              v         
+
+	.text
+	.syntax unified
+	.eabi_attribute	67, "2.09"
+	.eabi_attribute	6, 10
+	.eabi_attribute	7, 65
+	.eabi_attribute	8, 1
+	.eabi_attribute	9, 2
+	.fpu	neon
+	.eabi_attribute	34, 0
+	.eabi_attribute	17, 1
+	.eabi_attribute	20, 1
+	.eabi_attribute	21, 1
+	.eabi_attribute	23, 3
+	.eabi_attribute	24, 1
+	.eabi_attribute	25, 1
+	.eabi_attribute	38, 1
+	.eabi_attribute	18, 4
+	.eabi_attribute	26, 2
+	.eabi_attribute	14, 0
+	.file	"debug.c"
+	.globl	foo
+	.p2align	2
+	.type	foo,%function
+	.code	32
+foo:
+.Lfunc_begin0:
+	.file	1 "" "SRC_COMPDIR/debug.c"
+	.loc	1 1 0
+	.fnstart
+	.cfi_sections .debug_frame
+	.cfi_startproc
+	.loc	1 2 13 prologue_end
+	add	r0, r1, r0
+.Ltmp0:
+	.loc	1 3 13
+	add	r0, r0, r2
+.Ltmp1:
+	.loc	1 4 3
+	bx	lr
+.Ltmp2:
+.Lfunc_end0:
+	.size	foo, .Lfunc_end0-foo
+	.cfi_endproc
+	.cantunwind
+	.fnend
+
+	.globl	bar
+	.p2align	2
+	.type	bar,%function
+	.code	32
+bar:
+.Lfunc_begin1:
+	.loc	1 7 0
+	.fnstart
+	.cfi_startproc
+	.loc	1 8 4 prologue_end
+	add	r0, r0, #1
+.Ltmp3:
+	.loc	1 9 3
+	bx	lr
+.Ltmp4:
+.Lfunc_end1:
+	.size	bar, .Lfunc_end1-bar
+	.cfi_endproc
+	.cantunwind
+	.fnend
+
+	.section	.debug_str,"MS",%progbits,1
+.Linfo_string0:
+	.asciz	"clang version 10.0.0 (git at github.com:llvm/llvm-project.git e73f78acd34360f7450b81167d9dc858ccddc262)"
+.Linfo_string1:
+	.asciz	"SRC_COMPDIR/debug.c"
+.Linfo_string2:
+	.asciz	""
+.Linfo_string3:
+	.asciz	"foo"
+.Linfo_string4:
+	.asciz	"int"
+.Linfo_string5:
+	.asciz	"bar"
+.Linfo_string6:
+	.asciz	"a"
+.Linfo_string7:
+	.asciz	"b"
+.Linfo_string8:
+	.asciz	"c"
+.Linfo_string9:
+	.asciz	"x"
+.Linfo_string10:
+	.asciz	"y"
+	.section	.debug_loc,"",%progbits
+.Ldebug_loc0:
+	.long	.Lfunc_begin0-.Lfunc_begin0
+	.long	.Ltmp0-.Lfunc_begin0
+	.short	1
+	.byte	80
+	.long	0
+	.long	0
+.Ldebug_loc1:
+	.long	.Ltmp0-.Lfunc_begin0
+	.long	.Ltmp1-.Lfunc_begin0
+	.short	1
+	.byte	80
+	.long	0
+	.long	0
+.Ldebug_loc2:
+	.long	.Ltmp1-.Lfunc_begin0
+	.long	.Lfunc_end0-.Lfunc_begin0
+	.short	1
+	.byte	80
+	.long	0
+	.long	0
+	.section	.debug_abbrev,"",%progbits
+	.byte	1
+	.byte	17
+	.byte	1
+	.byte	37
+	.byte	14
+	.byte	19
+	.byte	5
+	.byte	3
+	.byte	14
+	.byte	16
+	.byte	23
+	.byte	27
+	.byte	14
+	.byte	17
+	.byte	1
+	.byte	18
+	.byte	6
+	.byte	0
+	.byte	0
+	.byte	2
+	.byte	46
+	.byte	1
+	.byte	17
+	.byte	1
+	.byte	18
+	.byte	6
+	.byte	64
+	.byte	24
+	.ascii	"\227B"
+	.byte	25
+	.byte	3
+	.byte	14
+	.byte	58
+	.byte	11
+	.byte	59
+	.byte	11
+	.byte	39
+	.byte	25
+	.byte	73
+	.byte	19
+	.byte	63
+	.byte	25
+	.byte	0
+	.byte	0
+	.byte	3
+	.byte	5
+	.byte	0
+	.byte	2
+	.byte	23
+	.byte	3
+	.byte	14
+	.byte	58
+	.byte	11
+	.byte	59
+	.byte	11
+	.byte	73
+	.byte	19
+	.byte	0
+	.byte	0
+	.byte	4
+	.byte	5
+	.byte	0
+	.byte	2
+	.byte	24
+	.byte	3
+	.byte	14
+	.byte	58
+	.byte	11
+	.byte	59
+	.byte	11
+	.byte	73
+	.byte	19
+	.byte	0
+	.byte	0
+	.byte	5
+	.byte	52
+	.byte	0
+	.byte	2
+	.byte	23
+	.byte	3
+	.byte	14
+	.byte	58
+	.byte	11
+	.byte	59
+	.byte	11
+	.byte	73
+	.byte	19
+	.byte	0
+	.byte	0
+	.byte	6
+	.byte	36
+	.byte	0
+	.byte	3
+	.byte	14
+	.byte	62
+	.byte	11
+	.byte	11
+	.byte	11
+	.byte	0
+	.byte	0
+	.byte	0
+	.section	.debug_info,"",%progbits
+.Lcu_begin0:
+	.long	.Ldebug_info_end0-.Ldebug_info_start0
+.Ldebug_info_start0:
+	.short	4
+	.long	.debug_abbrev
+	.byte	4
+	.byte	1
+	.long	.Linfo_string0
+	.short	12
+	.long	.Linfo_string1
+	.long	.Lline_table_start0
+	.long	.Linfo_string2
+	.long	.Lfunc_begin0
+	.long	.Lfunc_end1-.Lfunc_begin0
+	.byte	2
+	.long	.Lfunc_begin0
+	.long	.Lfunc_end0-.Lfunc_begin0
+	.byte	1
+	.byte	91
+
+	.long	.Linfo_string3
+	.byte	1
+	.byte	1
+
+	.long	166
+
+	.byte	3
+	.long	.Ldebug_loc0
+	.long	.Linfo_string6
+	.byte	1
+	.byte	1
+	.long	166
+	.byte	4
+	.byte	1
+	.byte	81
+	.long	.Linfo_string7
+	.byte	1
+	.byte	1
+	.long	166
+	.byte	4
+	.byte	1
+	.byte	82
+	.long	.Linfo_string8
+	.byte	1
+	.byte	1
+	.long	166
+	.byte	5
+	.long	.Ldebug_loc1
+	.long	.Linfo_string9
+	.byte	1
+	.byte	2
+	.long	166
+	.byte	5
+	.long	.Ldebug_loc2
+	.long	.Linfo_string10
+	.byte	1
+	.byte	3
+	.long	166
+	.byte	0
+	.byte	2
+	.long	.Lfunc_begin1
+	.long	.Lfunc_end1-.Lfunc_begin1
+	.byte	1
+	.byte	91
+
+	.long	.Linfo_string5
+	.byte	1
+	.byte	7
+
+	.long	166
+
+	.byte	4
+	.byte	1
+	.byte	80
+	.long	.Linfo_string6
+	.byte	1
+	.byte	7
+	.long	166
+	.byte	0
+	.byte	6
+	.long	.Linfo_string4
+	.byte	5
+	.byte	4
+	.byte	0
+.Ldebug_info_end0:
+	.ident	"clang version 10.0.0 (git at github.com:llvm/llvm-project.git e73f78acd34360f7450b81167d9dc858ccddc262)"
+	.section	".note.GNU-stack","",%progbits
+	.addrsig
+	.eabi_attribute	30, 1
+	.section	.debug_line,"",%progbits
+.Lline_table_start0:

diff  --git a/llvm/test/tools/llvm-objdump/ARM/debug-vars-dwarf5-sections.s b/llvm/test/tools/llvm-objdump/ARM/debug-vars-dwarf5-sections.s
new file mode 100644
index 000000000000..a9e08ff95556
--- /dev/null
+++ b/llvm/test/tools/llvm-objdump/ARM/debug-vars-dwarf5-sections.s
@@ -0,0 +1,411 @@
+## Check that the --debug-vars option works for simple register locations, when
+## using DWARF4 debug info, with functions in multiple sections.
+
+## Generated with this compile command, with the source code in Inputs/debug.c:
+## clang --target=arm--none-eabi -march=armv7-a -c debug.c -O1 -gdwarf-5 -S -o - -ffunction-sections
+
+# RUN: llvm-mc -triple armv8a--none-eabi < %s -filetype=obj --dwarf-version=5 | \
+# RUN:     llvm-objdump - -d --debug-vars --no-show-raw-insn | \
+# RUN:     FileCheck %s
+
+# CHECK: Disassembly of section .text.foo:
+# CHECK-EMPTY:
+# CHECK-NEXT: 00000000 <foo>:
+# CHECK-NEXT:                                                                   ┠─ a = R0
+# CHECK-NEXT:                                                                   ┃ ┠─ b = R1
+# CHECK-NEXT:                                                                   ┃ ┃ ┠─ c = R2
+# CHECK-NEXT:                                                                   ┃ ┃ ┃ ┌─ x = R0
+# CHECK-NEXT:        0:       add     r0, r1, r0                                ┻ ┃ ┃ ╈
+# CHECK-NEXT:                                                                   ┌─ y = R0
+# CHECK-NEXT:        4:       add     r0, r0, r2                                ╈ ┃ ┃ ┻
+# CHECK-NEXT:        8:       bx      lr                                        ┻ ┻ ┻
+# CHECK-EMPTY:
+# CHECK-NEXT: Disassembly of section .text.bar:
+# CHECK-EMPTY:
+# CHECK-NEXT: 00000000 <bar>:
+# CHECK-NEXT:                                                                   ┠─ a = R0
+# CHECK-NEXT:        0:       add     r0, r0, #1                                ┃
+# CHECK-NEXT:        4:       bx      lr                                        ┻
+
+	.text
+	.syntax unified
+	.eabi_attribute	67, "2.09"
+	.eabi_attribute	6, 10
+	.eabi_attribute	7, 65
+	.eabi_attribute	8, 1
+	.eabi_attribute	9, 2
+	.fpu	neon
+	.eabi_attribute	34, 0
+	.eabi_attribute	17, 1
+	.eabi_attribute	20, 1
+	.eabi_attribute	21, 1
+	.eabi_attribute	23, 3
+	.eabi_attribute	24, 1
+	.eabi_attribute	25, 1
+	.eabi_attribute	38, 1
+	.eabi_attribute	18, 4
+	.eabi_attribute	26, 2
+	.eabi_attribute	14, 0
+	.file	"debug.c"
+	.section	.text.foo,"ax",%progbits
+	.globl	foo
+	.p2align	2
+	.type	foo,%function
+	.code	32
+foo:
+.Lfunc_begin0:
+	.file	0 "/work/scratch" "/work/llvm/src/llvm/test/tools/llvm-objdump/ARM/Inputs/debug.c" md5 0x07374f01ab24ec7c07db73bc13bd778e
+	.file	1 "/work" "llvm/src/llvm/test/tools/llvm-objdump/ARM/Inputs/debug.c" md5 0x07374f01ab24ec7c07db73bc13bd778e
+	.loc	1 1 0
+	.fnstart
+	.cfi_sections .debug_frame
+	.cfi_startproc
+	.loc	1 2 13 prologue_end
+	add	r0, r1, r0
+.Ltmp0:
+	.loc	1 3 13
+	add	r0, r0, r2
+.Ltmp1:
+	.loc	1 4 3
+	bx	lr
+.Ltmp2:
+.Lfunc_end0:
+	.size	foo, .Lfunc_end0-foo
+	.cfi_endproc
+	.cantunwind
+	.fnend
+
+	.section	.text.bar,"ax",%progbits
+	.globl	bar
+	.p2align	2
+	.type	bar,%function
+	.code	32
+bar:
+.Lfunc_begin1:
+	.loc	1 7 0
+	.fnstart
+	.cfi_startproc
+	.loc	1 8 4 prologue_end
+	add	r0, r0, #1
+.Ltmp3:
+	.loc	1 9 3
+	bx	lr
+.Ltmp4:
+.Lfunc_end1:
+	.size	bar, .Lfunc_end1-bar
+	.cfi_endproc
+	.cantunwind
+	.fnend
+
+	.section	.debug_str_offsets,"",%progbits
+	.long	48
+	.short	5
+	.short	0
+.Lstr_offsets_base0:
+	.section	.debug_str,"MS",%progbits,1
+.Linfo_string0:
+	.asciz	"clang version 10.0.0 (git at github.com:llvm/llvm-project.git e73f78acd34360f7450b81167d9dc858ccddc262)"
+.Linfo_string1:
+	.asciz	"/work/llvm/src/llvm/test/tools/llvm-objdump/ARM/Inputs/debug.c"
+.Linfo_string2:
+	.asciz	"/work/scratch"
+.Linfo_string3:
+	.asciz	"foo"
+.Linfo_string4:
+	.asciz	"int"
+.Linfo_string5:
+	.asciz	"bar"
+.Linfo_string6:
+	.asciz	"a"
+.Linfo_string7:
+	.asciz	"b"
+.Linfo_string8:
+	.asciz	"c"
+.Linfo_string9:
+	.asciz	"x"
+.Linfo_string10:
+	.asciz	"y"
+	.section	.debug_str_offsets,"",%progbits
+	.long	.Linfo_string0
+	.long	.Linfo_string1
+	.long	.Linfo_string2
+	.long	.Linfo_string3
+	.long	.Linfo_string4
+	.long	.Linfo_string5
+	.long	.Linfo_string6
+	.long	.Linfo_string7
+	.long	.Linfo_string8
+	.long	.Linfo_string9
+	.long	.Linfo_string10
+	.section	.debug_loclists,"",%progbits
+	.long	.Ldebug_loclist_table_end0-.Ldebug_loclist_table_start0
+.Ldebug_loclist_table_start0:
+	.short	5
+	.byte	4
+	.byte	0
+	.long	3
+.Lloclists_table_base0:
+	.long	.Ldebug_loc0-.Lloclists_table_base0
+	.long	.Ldebug_loc1-.Lloclists_table_base0
+	.long	.Ldebug_loc2-.Lloclists_table_base0
+.Ldebug_loc0:
+	.byte	3
+	.byte	0
+	.uleb128 .Ltmp0-.Lfunc_begin0
+	.byte	1
+	.byte	80
+	.byte	0
+.Ldebug_loc1:
+	.byte	1
+	.byte	0
+	.byte	4
+	.uleb128 .Ltmp0-.Lfunc_begin0
+	.uleb128 .Ltmp1-.Lfunc_begin0
+	.byte	1
+	.byte	80
+	.byte	0
+.Ldebug_loc2:
+	.byte	1
+	.byte	0
+	.byte	4
+	.uleb128 .Ltmp1-.Lfunc_begin0
+	.uleb128 .Lfunc_end0-.Lfunc_begin0
+	.byte	1
+	.byte	80
+	.byte	0
+.Ldebug_loclist_table_end0:
+	.section	.debug_abbrev,"",%progbits
+	.byte	1
+	.byte	17
+	.byte	1
+	.byte	37
+	.byte	37
+	.byte	19
+	.byte	5
+	.byte	3
+	.byte	37
+	.byte	114
+	.byte	23
+	.byte	16
+	.byte	23
+	.byte	27
+	.byte	37
+	.byte	17
+	.byte	1
+	.byte	85
+	.byte	35
+	.byte	115
+	.byte	23
+	.byte	116
+	.byte	23
+	.ascii	"\214\001"
+	.byte	23
+	.byte	0
+	.byte	0
+	.byte	2
+	.byte	46
+	.byte	1
+	.byte	17
+	.byte	27
+	.byte	18
+	.byte	6
+	.byte	64
+	.byte	24
+	.byte	122
+	.byte	25
+	.byte	3
+	.byte	37
+	.byte	58
+	.byte	11
+	.byte	59
+	.byte	11
+	.byte	39
+	.byte	25
+	.byte	73
+	.byte	19
+	.byte	63
+	.byte	25
+	.byte	0
+	.byte	0
+	.byte	3
+	.byte	5
+	.byte	0
+	.byte	2
+	.byte	34
+	.byte	3
+	.byte	37
+	.byte	58
+	.byte	11
+	.byte	59
+	.byte	11
+	.byte	73
+	.byte	19
+	.byte	0
+	.byte	0
+	.byte	4
+	.byte	5
+	.byte	0
+	.byte	2
+	.byte	24
+	.byte	3
+	.byte	37
+	.byte	58
+	.byte	11
+	.byte	59
+	.byte	11
+	.byte	73
+	.byte	19
+	.byte	0
+	.byte	0
+	.byte	5
+	.byte	52
+	.byte	0
+	.byte	2
+	.byte	34
+	.byte	3
+	.byte	37
+	.byte	58
+	.byte	11
+	.byte	59
+	.byte	11
+	.byte	73
+	.byte	19
+	.byte	0
+	.byte	0
+	.byte	6
+	.byte	36
+	.byte	0
+	.byte	3
+	.byte	37
+	.byte	62
+	.byte	11
+	.byte	11
+	.byte	11
+	.byte	0
+	.byte	0
+	.byte	0
+	.section	.debug_info,"",%progbits
+.Lcu_begin0:
+	.long	.Ldebug_info_end0-.Ldebug_info_start0
+.Ldebug_info_start0:
+	.short	5
+	.byte	1
+	.byte	4
+	.long	.debug_abbrev
+	.byte	1
+	.byte	0
+	.short	12
+	.byte	1
+	.long	.Lstr_offsets_base0
+	.long	.Lline_table_start0
+	.byte	2
+	.long	0
+	.byte	0
+	.long	.Laddr_table_base0
+	.long	.Lrnglists_table_base0
+	.long	.Lloclists_table_base0
+	.byte	2
+	.byte	0
+	.long	.Lfunc_end0-.Lfunc_begin0
+	.byte	1
+	.byte	91
+
+	.byte	3
+	.byte	1
+	.byte	1
+
+	.long	132
+
+	.byte	3
+	.byte	0
+	.byte	6
+	.byte	1
+	.byte	1
+	.long	132
+	.byte	4
+	.byte	1
+	.byte	81
+	.byte	7
+	.byte	1
+	.byte	1
+	.long	132
+	.byte	4
+	.byte	1
+	.byte	82
+	.byte	8
+	.byte	1
+	.byte	1
+	.long	132
+	.byte	5
+	.byte	1
+	.byte	9
+	.byte	1
+	.byte	2
+	.long	132
+	.byte	5
+	.byte	2
+	.byte	10
+	.byte	1
+	.byte	3
+	.long	132
+	.byte	0
+	.byte	2
+	.byte	1
+	.long	.Lfunc_end1-.Lfunc_begin1
+	.byte	1
+	.byte	91
+
+	.byte	5
+	.byte	1
+	.byte	7
+
+	.long	132
+
+	.byte	4
+	.byte	1
+	.byte	80
+	.byte	6
+	.byte	1
+	.byte	7
+	.long	132
+	.byte	0
+	.byte	6
+	.byte	4
+	.byte	5
+	.byte	4
+	.byte	0
+.Ldebug_info_end0:
+	.section	.debug_rnglists,"",%progbits
+	.long	.Ldebug_rnglist_table_end0-.Ldebug_rnglist_table_start0
+.Ldebug_rnglist_table_start0:
+	.short	5
+	.byte	4
+	.byte	0
+	.long	1
+.Lrnglists_table_base0:
+	.long	.Ldebug_ranges0-.Lrnglists_table_base0
+.Ldebug_ranges0:
+	.byte	3
+	.byte	0
+	.uleb128 .Lfunc_end0-.Lfunc_begin0
+	.byte	3
+	.byte	1
+	.uleb128 .Lfunc_end1-.Lfunc_begin1
+	.byte	0
+.Ldebug_rnglist_table_end0:
+	.section	.debug_addr,"",%progbits
+	.long	.Ldebug_addr_end0-.Ldebug_addr_start0
+.Ldebug_addr_start0:
+	.short	5
+	.byte	4
+	.byte	0
+.Laddr_table_base0:
+	.long	.Lfunc_begin0
+	.long	.Lfunc_begin1
+.Ldebug_addr_end0:
+	.ident	"clang version 10.0.0 (git at github.com:llvm/llvm-project.git e73f78acd34360f7450b81167d9dc858ccddc262)"
+	.section	".note.GNU-stack","",%progbits
+	.addrsig
+	.eabi_attribute	30, 1
+	.section	.debug_line,"",%progbits
+.Lline_table_start0:

diff  --git a/llvm/test/tools/llvm-objdump/ARM/debug-vars-dwarf5.s b/llvm/test/tools/llvm-objdump/ARM/debug-vars-dwarf5.s
new file mode 100644
index 000000000000..8a63a4ee9ec0
--- /dev/null
+++ b/llvm/test/tools/llvm-objdump/ARM/debug-vars-dwarf5.s
@@ -0,0 +1,382 @@
+## Check that the --debug-vars option works for simple register locations, when
+## using DWARF5 debug info, with multiple functions in one section.
+
+## Generated with this compile command, with the source code in Inputs/debug.c:
+## clang --target=arm--none-eabi -march=armv7-a -c debug.c -O1 -gdwarf-3 -S -o -
+
+# RUN: llvm-mc -triple armv8a--none-eabi < %s -filetype=obj --dwarf-version=5 | \
+# RUN:     llvm-objdump - -d --debug-vars --no-show-raw-insn | \
+# RUN:     FileCheck %s
+
+# CHECK: Disassembly of section .text:
+# CHECK-EMPTY:
+# CHECK-NEXT: 00000000 <foo>:
+# CHECK-NEXT:                                                                   ┠─ a = R0
+# CHECK-NEXT:                                                                   ┃ ┠─ b = R1
+# CHECK-NEXT:                                                                   ┃ ┃ ┠─ c = R2
+# CHECK-NEXT:                                                                   ┃ ┃ ┃ ┌─ x = R0
+# CHECK-NEXT:        0:       add     r0, r1, r0                                ┻ ┃ ┃ ╈
+# CHECK-NEXT:                                                                   ┌─ y = R0
+# CHECK-NEXT:        4:       add     r0, r0, r2                                ╈ ┃ ┃ ┻
+# CHECK-NEXT:        8:       bx      lr                                        ┻ ┻ ┻
+# CHECK-EMPTY:
+# CHECK-NEXT: 0000000c <bar>:
+# CHECK-NEXT:                                                                   ┠─ a = R0
+# CHECK-NEXT:        c:       add     r0, r0, #1                                ┃
+# CHECK-NEXT:       10:       bx      lr                                        ┻
+
+	.text
+	.syntax unified
+	.eabi_attribute	67, "2.09"
+	.eabi_attribute	6, 10
+	.eabi_attribute	7, 65
+	.eabi_attribute	8, 1
+	.eabi_attribute	9, 2
+	.fpu	neon
+	.eabi_attribute	34, 0
+	.eabi_attribute	17, 1
+	.eabi_attribute	20, 1
+	.eabi_attribute	21, 1
+	.eabi_attribute	23, 3
+	.eabi_attribute	24, 1
+	.eabi_attribute	25, 1
+	.eabi_attribute	38, 1
+	.eabi_attribute	18, 4
+	.eabi_attribute	26, 2
+	.eabi_attribute	14, 0
+	.file	"debug.c"
+	.globl	foo
+	.p2align	2
+	.type	foo,%function
+	.code	32
+foo:
+.Lfunc_begin0:
+	.file	0 "/work/scratch" "/work/llvm/src/llvm/test/tools/llvm-objdump/ARM/Inputs/debug.c" md5 0x07374f01ab24ec7c07db73bc13bd778e
+	.file	1 "/work" "llvm/src/llvm/test/tools/llvm-objdump/ARM/Inputs/debug.c" md5 0x07374f01ab24ec7c07db73bc13bd778e
+	.loc	1 1 0
+	.fnstart
+	.cfi_sections .debug_frame
+	.cfi_startproc
+	.loc	1 2 13 prologue_end
+	add	r0, r1, r0
+.Ltmp0:
+	.loc	1 3 13
+	add	r0, r0, r2
+.Ltmp1:
+	.loc	1 4 3
+	bx	lr
+.Ltmp2:
+.Lfunc_end0:
+	.size	foo, .Lfunc_end0-foo
+	.cfi_endproc
+	.cantunwind
+	.fnend
+
+	.globl	bar
+	.p2align	2
+	.type	bar,%function
+	.code	32
+bar:
+.Lfunc_begin1:
+	.loc	1 7 0
+	.fnstart
+	.cfi_startproc
+	.loc	1 8 4 prologue_end
+	add	r0, r0, #1
+.Ltmp3:
+	.loc	1 9 3
+	bx	lr
+.Ltmp4:
+.Lfunc_end1:
+	.size	bar, .Lfunc_end1-bar
+	.cfi_endproc
+	.cantunwind
+	.fnend
+
+	.section	.debug_str_offsets,"",%progbits
+	.long	48
+	.short	5
+	.short	0
+.Lstr_offsets_base0:
+	.section	.debug_str,"MS",%progbits,1
+.Linfo_string0:
+	.asciz	"clang version 10.0.0 (git at github.com:llvm/llvm-project.git e73f78acd34360f7450b81167d9dc858ccddc262)"
+.Linfo_string1:
+	.asciz	"/work/llvm/src/llvm/test/tools/llvm-objdump/ARM/Inputs/debug.c"
+.Linfo_string2:
+	.asciz	"/work/scratch"
+.Linfo_string3:
+	.asciz	"foo"
+.Linfo_string4:
+	.asciz	"int"
+.Linfo_string5:
+	.asciz	"bar"
+.Linfo_string6:
+	.asciz	"a"
+.Linfo_string7:
+	.asciz	"b"
+.Linfo_string8:
+	.asciz	"c"
+.Linfo_string9:
+	.asciz	"x"
+.Linfo_string10:
+	.asciz	"y"
+	.section	.debug_str_offsets,"",%progbits
+	.long	.Linfo_string0
+	.long	.Linfo_string1
+	.long	.Linfo_string2
+	.long	.Linfo_string3
+	.long	.Linfo_string4
+	.long	.Linfo_string5
+	.long	.Linfo_string6
+	.long	.Linfo_string7
+	.long	.Linfo_string8
+	.long	.Linfo_string9
+	.long	.Linfo_string10
+	.section	.debug_loclists,"",%progbits
+	.long	.Ldebug_loclist_table_end0-.Ldebug_loclist_table_start0
+.Ldebug_loclist_table_start0:
+	.short	5
+	.byte	4
+	.byte	0
+	.long	3
+.Lloclists_table_base0:
+	.long	.Ldebug_loc0-.Lloclists_table_base0
+	.long	.Ldebug_loc1-.Lloclists_table_base0
+	.long	.Ldebug_loc2-.Lloclists_table_base0
+.Ldebug_loc0:
+	.byte	4
+	.uleb128 .Lfunc_begin0-.Lfunc_begin0
+	.uleb128 .Ltmp0-.Lfunc_begin0
+	.byte	1
+	.byte	80
+	.byte	0
+.Ldebug_loc1:
+	.byte	4
+	.uleb128 .Ltmp0-.Lfunc_begin0
+	.uleb128 .Ltmp1-.Lfunc_begin0
+	.byte	1
+	.byte	80
+	.byte	0
+.Ldebug_loc2:
+	.byte	4
+	.uleb128 .Ltmp1-.Lfunc_begin0
+	.uleb128 .Lfunc_end0-.Lfunc_begin0
+	.byte	1
+	.byte	80
+	.byte	0
+.Ldebug_loclist_table_end0:
+	.section	.debug_abbrev,"",%progbits
+	.byte	1
+	.byte	17
+	.byte	1
+	.byte	37
+	.byte	37
+	.byte	19
+	.byte	5
+	.byte	3
+	.byte	37
+	.byte	114
+	.byte	23
+	.byte	16
+	.byte	23
+	.byte	27
+	.byte	37
+	.byte	17
+	.byte	27
+	.byte	18
+	.byte	6
+	.byte	115
+	.byte	23
+	.ascii	"\214\001"
+	.byte	23
+	.byte	0
+	.byte	0
+	.byte	2
+	.byte	46
+	.byte	1
+	.byte	17
+	.byte	27
+	.byte	18
+	.byte	6
+	.byte	64
+	.byte	24
+	.byte	122
+	.byte	25
+	.byte	3
+	.byte	37
+	.byte	58
+	.byte	11
+	.byte	59
+	.byte	11
+	.byte	39
+	.byte	25
+	.byte	73
+	.byte	19
+	.byte	63
+	.byte	25
+	.byte	0
+	.byte	0
+	.byte	3
+	.byte	5
+	.byte	0
+	.byte	2
+	.byte	34
+	.byte	3
+	.byte	37
+	.byte	58
+	.byte	11
+	.byte	59
+	.byte	11
+	.byte	73
+	.byte	19
+	.byte	0
+	.byte	0
+	.byte	4
+	.byte	5
+	.byte	0
+	.byte	2
+	.byte	24
+	.byte	3
+	.byte	37
+	.byte	58
+	.byte	11
+	.byte	59
+	.byte	11
+	.byte	73
+	.byte	19
+	.byte	0
+	.byte	0
+	.byte	5
+	.byte	52
+	.byte	0
+	.byte	2
+	.byte	34
+	.byte	3
+	.byte	37
+	.byte	58
+	.byte	11
+	.byte	59
+	.byte	11
+	.byte	73
+	.byte	19
+	.byte	0
+	.byte	0
+	.byte	6
+	.byte	36
+	.byte	0
+	.byte	3
+	.byte	37
+	.byte	62
+	.byte	11
+	.byte	11
+	.byte	11
+	.byte	0
+	.byte	0
+	.byte	0
+	.section	.debug_info,"",%progbits
+.Lcu_begin0:
+	.long	.Ldebug_info_end0-.Ldebug_info_start0
+.Ldebug_info_start0:
+	.short	5
+	.byte	1
+	.byte	4
+	.long	.debug_abbrev
+	.byte	1
+	.byte	0
+	.short	12
+	.byte	1
+	.long	.Lstr_offsets_base0
+	.long	.Lline_table_start0
+	.byte	2
+	.byte	0
+	.long	.Lfunc_end1-.Lfunc_begin0
+	.long	.Laddr_table_base0
+	.long	.Lloclists_table_base0
+	.byte	2
+	.byte	0
+	.long	.Lfunc_end0-.Lfunc_begin0
+	.byte	1
+	.byte	91
+
+	.byte	3
+	.byte	1
+	.byte	1
+
+	.long	128
+
+	.byte	3
+	.byte	0
+	.byte	6
+	.byte	1
+	.byte	1
+	.long	128
+	.byte	4
+	.byte	1
+	.byte	81
+	.byte	7
+	.byte	1
+	.byte	1
+	.long	128
+	.byte	4
+	.byte	1
+	.byte	82
+	.byte	8
+	.byte	1
+	.byte	1
+	.long	128
+	.byte	5
+	.byte	1
+	.byte	9
+	.byte	1
+	.byte	2
+	.long	128
+	.byte	5
+	.byte	2
+	.byte	10
+	.byte	1
+	.byte	3
+	.long	128
+	.byte	0
+	.byte	2
+	.byte	1
+	.long	.Lfunc_end1-.Lfunc_begin1
+	.byte	1
+	.byte	91
+
+	.byte	5
+	.byte	1
+	.byte	7
+
+	.long	128
+
+	.byte	4
+	.byte	1
+	.byte	80
+	.byte	6
+	.byte	1
+	.byte	7
+	.long	128
+	.byte	0
+	.byte	6
+	.byte	4
+	.byte	5
+	.byte	4
+	.byte	0
+.Ldebug_info_end0:
+	.section	.debug_addr,"",%progbits
+	.long	.Ldebug_addr_end0-.Ldebug_addr_start0
+.Ldebug_addr_start0:
+	.short	5
+	.byte	4
+	.byte	0
+.Laddr_table_base0:
+	.long	.Lfunc_begin0
+	.long	.Lfunc_begin1
+.Ldebug_addr_end0:
+	.ident	"clang version 10.0.0 (git at github.com:llvm/llvm-project.git e73f78acd34360f7450b81167d9dc858ccddc262)"
+	.section	".note.GNU-stack","",%progbits
+	.addrsig
+	.eabi_attribute	30, 1
+	.section	.debug_line,"",%progbits
+.Lline_table_start0:

diff  --git a/llvm/test/tools/llvm-objdump/ARM/debug-vars-wide-chars.s b/llvm/test/tools/llvm-objdump/ARM/debug-vars-wide-chars.s
new file mode 100644
index 000000000000..2573dc63513e
--- /dev/null
+++ b/llvm/test/tools/llvm-objdump/ARM/debug-vars-wide-chars.s
@@ -0,0 +1,232 @@
+# RUN: mkdir -p %t/a
+# RUN: cp %p/Inputs/wide-char.c %t/a/wide-char.c
+# RUN: sed -e "s,SRC_COMPDIR,%/t/a,g" %s > %t.s
+# RUN: llvm-mc -triple armv8a--none-eabi < %t.s -filetype=obj | \
+# RUN:     llvm-objdump - -d --debug-vars --source | \
+# RUN:     FileCheck %s --strict-whitespace
+
+## The Chinese character in the source does not print correctly on Windows.
+# UNSUPPORTED: system-windows
+
+## Check that the --debug-vars option correctly aligns the variable display when
+## the source code (printed by the -S option) includes East Asian wide
+## characters.
+
+# CHECK: 00000000 <foo>:
+# CHECK-NEXT: ;   return *喵;                                                 ┠─ 喵 = R0
+# CHECK-NEXT:        0: 00 00 90 e5  	ldr	r0, [r0]                        ┻   
+# CHECK-NEXT:        4: 1e ff 2f e1  	bx	lr                                  
+
+	.text
+	.syntax unified
+	.eabi_attribute	67, "2.09"
+	.eabi_attribute	6, 10
+	.eabi_attribute	7, 65
+	.eabi_attribute	8, 1
+	.eabi_attribute	9, 2
+	.fpu	vfpv3
+	.eabi_attribute	34, 0
+	.eabi_attribute	17, 1
+	.eabi_attribute	20, 1
+	.eabi_attribute	21, 1
+	.eabi_attribute	23, 3
+	.eabi_attribute	24, 1
+	.eabi_attribute	25, 1
+	.eabi_attribute	38, 1
+	.eabi_attribute	18, 4
+	.eabi_attribute	26, 2
+	.eabi_attribute	14, 0
+	.file	"wide.c"
+	.globl	foo
+	.p2align	2
+	.type	foo,%function
+	.code	32
+foo:
+.Lfunc_begin0:
+	.file	1 "SRC_COMPDIR/wide-char.c"
+	.loc	1 1 0
+	.fnstart
+	.cfi_sections .debug_frame
+	.cfi_startproc
+	.loc	1 2 10 prologue_end
+	ldr	r0, [r0]
+.Ltmp0:
+	.loc	1 2 3 is_stmt 0
+	bx	lr
+.Ltmp1:
+.Lfunc_end0:
+	.size	foo, .Lfunc_end0-foo
+	.cfi_endproc
+	.cantunwind
+	.fnend
+
+	.section	.debug_str,"MS",%progbits,1
+.Linfo_string0:
+	.asciz	"clang version 6.0.0-1ubuntu2 (tags/RELEASE_600/final)"
+.Linfo_string1:
+	.asciz	"wide-char.c"
+.Linfo_string2:
+	.asciz	"SRC_COMPDIR"
+.Linfo_string3:
+	.asciz	"foo"
+.Linfo_string4:
+	.asciz	"int"
+.Linfo_string5:
+	.asciz	"\345\226\265"
+	.section	.debug_loc,"",%progbits
+.Ldebug_loc0:
+	.long	.Lfunc_begin0-.Lfunc_begin0
+	.long	.Ltmp0-.Lfunc_begin0
+	.short	1
+	.byte	80
+	.long	0
+	.long	0
+	.section	.debug_abbrev,"",%progbits
+	.byte	1
+	.byte	17
+	.byte	1
+	.byte	37
+	.byte	14
+	.byte	19
+	.byte	5
+	.byte	3
+	.byte	14
+	.byte	16
+	.byte	23
+	.byte	27
+	.byte	14
+	.ascii	"\264B"
+	.byte	25
+	.byte	17
+	.byte	1
+	.byte	18
+	.byte	6
+	.byte	0
+	.byte	0
+	.byte	2
+	.byte	46
+	.byte	1
+	.byte	17
+	.byte	1
+	.byte	18
+	.byte	6
+	.byte	64
+	.byte	24
+	.byte	3
+	.byte	14
+	.byte	58
+	.byte	11
+	.byte	59
+	.byte	11
+	.byte	39
+	.byte	25
+	.byte	73
+	.byte	19
+	.byte	63
+	.byte	25
+	.byte	0
+	.byte	0
+	.byte	3
+	.byte	5
+	.byte	0
+	.byte	2
+	.byte	23
+	.byte	3
+	.byte	14
+	.byte	58
+	.byte	11
+	.byte	59
+	.byte	11
+	.byte	73
+	.byte	19
+	.byte	0
+	.byte	0
+	.byte	4
+	.byte	36
+	.byte	0
+	.byte	3
+	.byte	14
+	.byte	62
+	.byte	11
+	.byte	11
+	.byte	11
+	.byte	0
+	.byte	0
+	.byte	5
+	.byte	15
+	.byte	0
+	.byte	73
+	.byte	19
+	.byte	0
+	.byte	0
+	.byte	0
+	.section	.debug_info,"",%progbits
+.Lcu_begin0:
+	.long	84
+	.short	4
+	.long	.debug_abbrev
+	.byte	4
+	.byte	1
+	.long	.Linfo_string0
+	.short	12
+	.long	.Linfo_string1
+	.long	.Lline_table_start0
+	.long	.Linfo_string2
+
+	.long	.Lfunc_begin0
+	.long	.Lfunc_end0-.Lfunc_begin0
+	.byte	2
+	.long	.Lfunc_begin0
+	.long	.Lfunc_end0-.Lfunc_begin0
+	.byte	1
+	.byte	91
+	.long	.Linfo_string3
+	.byte	1
+	.byte	1
+
+	.long	75
+
+	.byte	3
+	.long	.Ldebug_loc0
+	.long	.Linfo_string5
+	.byte	1
+	.byte	1
+	.long	82
+	.byte	0
+	.byte	4
+	.long	.Linfo_string4
+	.byte	5
+	.byte	4
+	.byte	5
+	.long	75
+	.byte	0
+	.section	.debug_ranges,"",%progbits
+	.section	.debug_macinfo,"",%progbits
+.Lcu_macro_begin0:
+	.byte	0
+	.section	.debug_pubnames,"",%progbits
+	.long	.LpubNames_end0-.LpubNames_begin0
+.LpubNames_begin0:
+	.short	2
+	.long	.Lcu_begin0
+	.long	88
+	.long	38
+	.asciz	"foo"
+	.long	0
+.LpubNames_end0:
+	.section	.debug_pubtypes,"",%progbits
+	.long	.LpubTypes_end0-.LpubTypes_begin0
+.LpubTypes_begin0:
+	.short	2
+	.long	.Lcu_begin0
+	.long	88
+	.long	75
+	.asciz	"int"
+	.long	0
+.LpubTypes_end0:
+
+	.ident	"clang version 6.0.0-1ubuntu2 (tags/RELEASE_600/final)"
+	.section	".note.GNU-stack","",%progbits
+	.eabi_attribute	30, 1
+	.section	.debug_line,"",%progbits
+.Lline_table_start0:

diff  --git a/llvm/test/tools/llvm-objdump/PowerPC/debug-vars.s b/llvm/test/tools/llvm-objdump/PowerPC/debug-vars.s
new file mode 100644
index 000000000000..6c3d326843c7
--- /dev/null
+++ b/llvm/test/tools/llvm-objdump/PowerPC/debug-vars.s
@@ -0,0 +1,372 @@
+## Check that the --debug-vars option works for simple register locations, when
+## using DWARF4 debug info, with multiple functions in one section.
+
+## Generated with this compile command and source code:
+## clang --target=arm--none-eabi -march=armv7-a -c debug.c -O1 -gdwarf-3 -S -o -
+
+## clang --target=powerpc64-unknown-linux -c debug.c -O1 -S -o -
+
+## int foo(int a, int b, int c) {
+##   int x = a + b;
+##   int y = x + c;
+##   return y;
+## }
+##
+## int bar(int a) {
+##   a++;
+##   return a;
+## }
+
+# RUN: llvm-mc -triple powerpc64-unknown-linux < %s -filetype=obj | \
+# RUN:     llvm-objdump - -d --debug-vars --no-show-raw-insn | \
+# RUN:     FileCheck %s
+
+# CHECK: Disassembly of section .text:
+# CHECK-EMPTY:
+# CHECK-NEXT: 0000000000000000 <.text>:
+# CHECK-NEXT:                                                                   ┠─ a = S3
+# CHECK-NEXT:                                                                   ┃ ┠─ b = S4
+# CHECK-NEXT:                                                                   ┃ ┃ ┠─ c = S5
+# CHECK-NEXT:                                                                   ┃ ┃ ┃ ┌─ x = S3
+# CHECK-NEXT:        0:       add 3, 4, 3                                       ┻ ┃ ┃ ╈
+# CHECK-NEXT:                                                                   ┌─ y = S3
+# CHECK-NEXT:        4:       add 3, 3, 5                                       ╈ ┃ ┃ ┻
+# CHECK-NEXT:        8:       extsw 3, 3                                        ┻ ┃ ┃
+# CHECK-NEXT:        c:       blr                                                 ┃ ┃
+# CHECK-NEXT:                 ...
+# CHECK-NEXT:                                                                   ┠─ a = S3
+# CHECK-NEXT:       1c:       addi 3, 3, 1                                      ┃
+# CHECK-NEXT:       20:       extsw 3, 3                                        ┻
+# CHECK-NEXT:       24:       blr
+# CHECK-NEXT:                 ...
+
+	.text
+	.file	"debug.c"
+	.globl	foo                     # -- Begin function foo
+	.p2align	2
+	.type	foo, at function
+	.section	.opd,"aw", at progbits
+foo:                                    # @foo
+	.p2align	3
+	.quad	.Lfunc_begin0
+	.quad	.TOC. at tocbase
+	.quad	0
+	.text
+.Lfunc_begin0:
+	.file	1 "/work" "llvm/src/llvm/test/tools/llvm-objdump/ARM/Inputs/debug.c"
+	.loc	1 1 0                   # llvm/src/llvm/test/tools/llvm-objdump/ARM/Inputs/debug.c:1:0
+	.cfi_sections .debug_frame
+	.cfi_startproc
+# %bb.0:                                # %entry
+	#DEBUG_VALUE: foo:a <- $x3
+	#DEBUG_VALUE: foo:a <- $r3
+	#DEBUG_VALUE: foo:b <- $x4
+	#DEBUG_VALUE: foo:b <- $x4
+	#DEBUG_VALUE: foo:b <- $r4
+	#DEBUG_VALUE: foo:c <- $x5
+	#DEBUG_VALUE: foo:c <- $x5
+	#DEBUG_VALUE: foo:c <- $r5
+	.loc	1 2 13 prologue_end     # llvm/src/llvm/test/tools/llvm-objdump/ARM/Inputs/debug.c:2:13
+	add 3, 4, 3
+.Ltmp0:
+	#DEBUG_VALUE: foo:x <- $r3
+	.loc	1 3 13                  # llvm/src/llvm/test/tools/llvm-objdump/ARM/Inputs/debug.c:3:13
+	add 3, 3, 5
+.Ltmp1:
+	#DEBUG_VALUE: foo:y <- $r3
+	.loc	1 4 3                   # llvm/src/llvm/test/tools/llvm-objdump/ARM/Inputs/debug.c:4:3
+	extsw 3, 3
+.Ltmp2:
+	blr
+.Ltmp3:
+	.long	0
+	.quad	0
+.Lfunc_end0:
+	.size	foo, .Lfunc_end0-.Lfunc_begin0
+	.cfi_endproc
+                                        # -- End function
+	.globl	bar                     # -- Begin function bar
+	.p2align	2
+	.type	bar, at function
+	.section	.opd,"aw", at progbits
+bar:                                    # @bar
+	.p2align	3
+	.quad	.Lfunc_begin1
+	.quad	.TOC. at tocbase
+	.quad	0
+	.text
+.Lfunc_begin1:
+	.loc	1 7 0                   # llvm/src/llvm/test/tools/llvm-objdump/ARM/Inputs/debug.c:7:0
+	.cfi_startproc
+# %bb.0:                                # %entry
+	#DEBUG_VALUE: bar:a <- $x3
+	#DEBUG_VALUE: bar:a <- $r3
+	.loc	1 8 4 prologue_end      # llvm/src/llvm/test/tools/llvm-objdump/ARM/Inputs/debug.c:8:4
+	addi 3, 3, 1
+.Ltmp4:
+	#DEBUG_VALUE: bar:a <- $r3
+	.loc	1 9 3                   # llvm/src/llvm/test/tools/llvm-objdump/ARM/Inputs/debug.c:9:3
+	extsw 3, 3
+.Ltmp5:
+	blr
+.Ltmp6:
+	.long	0
+	.quad	0
+.Lfunc_end1:
+	.size	bar, .Lfunc_end1-.Lfunc_begin1
+	.cfi_endproc
+                                        # -- End function
+	.section	.debug_str,"MS", at progbits,1
+.Linfo_string0:
+	.asciz	"clang version 10.0.0 (git at github.com:llvm/llvm-project.git e73f78acd34360f7450b81167d9dc858ccddc262)" # string offset=0
+.Linfo_string1:
+	.asciz	"/work/llvm/src/llvm/test/tools/llvm-objdump/ARM/Inputs/debug.c" # string offset=101
+.Linfo_string2:
+	.asciz	"/work/scratch"         # string offset=164
+.Linfo_string3:
+	.asciz	"foo"                   # string offset=178
+.Linfo_string4:
+	.asciz	"int"                   # string offset=182
+.Linfo_string5:
+	.asciz	"bar"                   # string offset=186
+.Linfo_string6:
+	.asciz	"a"                     # string offset=190
+.Linfo_string7:
+	.asciz	"b"                     # string offset=192
+.Linfo_string8:
+	.asciz	"c"                     # string offset=194
+.Linfo_string9:
+	.asciz	"x"                     # string offset=196
+.Linfo_string10:
+	.asciz	"y"                     # string offset=198
+	.section	.debug_loc,"", at progbits
+.Ldebug_loc0:
+	.quad	.Lfunc_begin0-.Lfunc_begin0
+	.quad	.Ltmp0-.Lfunc_begin0
+	.short	3                       # Loc expr size
+	.byte	144                     # super-register DW_OP_regx
+	.byte	179                     # 1203
+	.byte	9                       #
+	.quad	0
+	.quad	0
+.Ldebug_loc1:
+	.quad	.Ltmp0-.Lfunc_begin0
+	.quad	.Ltmp1-.Lfunc_begin0
+	.short	3                       # Loc expr size
+	.byte	144                     # super-register DW_OP_regx
+	.byte	179                     # 1203
+	.byte	9                       #
+	.quad	0
+	.quad	0
+.Ldebug_loc2:
+	.quad	.Ltmp1-.Lfunc_begin0
+	.quad	.Ltmp2-.Lfunc_begin0
+	.short	3                       # Loc expr size
+	.byte	144                     # super-register DW_OP_regx
+	.byte	179                     # 1203
+	.byte	9                       #
+	.quad	0
+	.quad	0
+.Ldebug_loc3:
+	.quad	.Lfunc_begin1-.Lfunc_begin0
+	.quad	.Ltmp5-.Lfunc_begin0
+	.short	3                       # Loc expr size
+	.byte	144                     # super-register DW_OP_regx
+	.byte	179                     # 1203
+	.byte	9                       #
+	.quad	0
+	.quad	0
+	.section	.debug_abbrev,"", at progbits
+	.byte	1                       # Abbreviation Code
+	.byte	17                      # DW_TAG_compile_unit
+	.byte	1                       # DW_CHILDREN_yes
+	.byte	37                      # DW_AT_producer
+	.byte	14                      # DW_FORM_strp
+	.byte	19                      # DW_AT_language
+	.byte	5                       # DW_FORM_data2
+	.byte	3                       # DW_AT_name
+	.byte	14                      # DW_FORM_strp
+	.byte	16                      # DW_AT_stmt_list
+	.byte	23                      # DW_FORM_sec_offset
+	.byte	27                      # DW_AT_comp_dir
+	.byte	14                      # DW_FORM_strp
+	.byte	17                      # DW_AT_low_pc
+	.byte	1                       # DW_FORM_addr
+	.byte	18                      # DW_AT_high_pc
+	.byte	6                       # DW_FORM_data4
+	.byte	0                       # EOM(1)
+	.byte	0                       # EOM(2)
+	.byte	2                       # Abbreviation Code
+	.byte	46                      # DW_TAG_subprogram
+	.byte	1                       # DW_CHILDREN_yes
+	.byte	17                      # DW_AT_low_pc
+	.byte	1                       # DW_FORM_addr
+	.byte	18                      # DW_AT_high_pc
+	.byte	6                       # DW_FORM_data4
+	.byte	64                      # DW_AT_frame_base
+	.byte	24                      # DW_FORM_exprloc
+	.ascii	"\227B"                 # DW_AT_GNU_all_call_sites
+	.byte	25                      # DW_FORM_flag_present
+	.byte	3                       # DW_AT_name
+	.byte	14                      # DW_FORM_strp
+	.byte	58                      # DW_AT_decl_file
+	.byte	11                      # DW_FORM_data1
+	.byte	59                      # DW_AT_decl_line
+	.byte	11                      # DW_FORM_data1
+	.byte	39                      # DW_AT_prototyped
+	.byte	25                      # DW_FORM_flag_present
+	.byte	73                      # DW_AT_type
+	.byte	19                      # DW_FORM_ref4
+	.byte	63                      # DW_AT_external
+	.byte	25                      # DW_FORM_flag_present
+	.byte	0                       # EOM(1)
+	.byte	0                       # EOM(2)
+	.byte	3                       # Abbreviation Code
+	.byte	5                       # DW_TAG_formal_parameter
+	.byte	0                       # DW_CHILDREN_no
+	.byte	2                       # DW_AT_location
+	.byte	23                      # DW_FORM_sec_offset
+	.byte	3                       # DW_AT_name
+	.byte	14                      # DW_FORM_strp
+	.byte	58                      # DW_AT_decl_file
+	.byte	11                      # DW_FORM_data1
+	.byte	59                      # DW_AT_decl_line
+	.byte	11                      # DW_FORM_data1
+	.byte	73                      # DW_AT_type
+	.byte	19                      # DW_FORM_ref4
+	.byte	0                       # EOM(1)
+	.byte	0                       # EOM(2)
+	.byte	4                       # Abbreviation Code
+	.byte	5                       # DW_TAG_formal_parameter
+	.byte	0                       # DW_CHILDREN_no
+	.byte	2                       # DW_AT_location
+	.byte	24                      # DW_FORM_exprloc
+	.byte	3                       # DW_AT_name
+	.byte	14                      # DW_FORM_strp
+	.byte	58                      # DW_AT_decl_file
+	.byte	11                      # DW_FORM_data1
+	.byte	59                      # DW_AT_decl_line
+	.byte	11                      # DW_FORM_data1
+	.byte	73                      # DW_AT_type
+	.byte	19                      # DW_FORM_ref4
+	.byte	0                       # EOM(1)
+	.byte	0                       # EOM(2)
+	.byte	5                       # Abbreviation Code
+	.byte	52                      # DW_TAG_variable
+	.byte	0                       # DW_CHILDREN_no
+	.byte	2                       # DW_AT_location
+	.byte	23                      # DW_FORM_sec_offset
+	.byte	3                       # DW_AT_name
+	.byte	14                      # DW_FORM_strp
+	.byte	58                      # DW_AT_decl_file
+	.byte	11                      # DW_FORM_data1
+	.byte	59                      # DW_AT_decl_line
+	.byte	11                      # DW_FORM_data1
+	.byte	73                      # DW_AT_type
+	.byte	19                      # DW_FORM_ref4
+	.byte	0                       # EOM(1)
+	.byte	0                       # EOM(2)
+	.byte	6                       # Abbreviation Code
+	.byte	36                      # DW_TAG_base_type
+	.byte	0                       # DW_CHILDREN_no
+	.byte	3                       # DW_AT_name
+	.byte	14                      # DW_FORM_strp
+	.byte	62                      # DW_AT_encoding
+	.byte	11                      # DW_FORM_data1
+	.byte	11                      # DW_AT_byte_size
+	.byte	11                      # DW_FORM_data1
+	.byte	0                       # EOM(1)
+	.byte	0                       # EOM(2)
+	.byte	0                       # EOM(3)
+	.section	.debug_info,"", at progbits
+.Lcu_begin0:
+	.long	.Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit
+.Ldebug_info_start0:
+	.short	4                       # DWARF version number
+	.long	.debug_abbrev           # Offset Into Abbrev. Section
+	.byte	8                       # Address Size (in bytes)
+	.byte	1                       # Abbrev [1] 0xb:0xb5 DW_TAG_compile_unit
+	.long	.Linfo_string0          # DW_AT_producer
+	.short	12                      # DW_AT_language
+	.long	.Linfo_string1          # DW_AT_name
+	.long	.Lline_table_start0     # DW_AT_stmt_list
+	.long	.Linfo_string2          # DW_AT_comp_dir
+	.quad	.Lfunc_begin0           # DW_AT_low_pc
+	.long	.Lfunc_end1-.Lfunc_begin0 # DW_AT_high_pc
+	.byte	2                       # Abbrev [2] 0x2a:0x65 DW_TAG_subprogram
+	.quad	.Lfunc_begin0           # DW_AT_low_pc
+	.long	.Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc
+	.byte	1                       # DW_AT_frame_base
+	.byte	81
+                                        # DW_AT_GNU_all_call_sites
+	.long	.Linfo_string3          # DW_AT_name
+	.byte	1                       # DW_AT_decl_file
+	.byte	1                       # DW_AT_decl_line
+                                        # DW_AT_prototyped
+	.long	184                     # DW_AT_type
+                                        # DW_AT_external
+	.byte	3                       # Abbrev [3] 0x43:0xf DW_TAG_formal_parameter
+	.long	.Ldebug_loc0            # DW_AT_location
+	.long	.Linfo_string6          # DW_AT_name
+	.byte	1                       # DW_AT_decl_file
+	.byte	1                       # DW_AT_decl_line
+	.long	184                     # DW_AT_type
+	.byte	4                       # Abbrev [4] 0x52:0xf DW_TAG_formal_parameter
+	.byte	3                       # DW_AT_location
+	.byte	144
+	.ascii	"\264\t"
+	.long	.Linfo_string7          # DW_AT_name
+	.byte	1                       # DW_AT_decl_file
+	.byte	1                       # DW_AT_decl_line
+	.long	184                     # DW_AT_type
+	.byte	4                       # Abbrev [4] 0x61:0xf DW_TAG_formal_parameter
+	.byte	3                       # DW_AT_location
+	.byte	144
+	.ascii	"\265\t"
+	.long	.Linfo_string8          # DW_AT_name
+	.byte	1                       # DW_AT_decl_file
+	.byte	1                       # DW_AT_decl_line
+	.long	184                     # DW_AT_type
+	.byte	5                       # Abbrev [5] 0x70:0xf DW_TAG_variable
+	.long	.Ldebug_loc1            # DW_AT_location
+	.long	.Linfo_string9          # DW_AT_name
+	.byte	1                       # DW_AT_decl_file
+	.byte	2                       # DW_AT_decl_line
+	.long	184                     # DW_AT_type
+	.byte	5                       # Abbrev [5] 0x7f:0xf DW_TAG_variable
+	.long	.Ldebug_loc2            # DW_AT_location
+	.long	.Linfo_string10         # DW_AT_name
+	.byte	1                       # DW_AT_decl_file
+	.byte	3                       # DW_AT_decl_line
+	.long	184                     # DW_AT_type
+	.byte	0                       # End Of Children Mark
+	.byte	2                       # Abbrev [2] 0x8f:0x29 DW_TAG_subprogram
+	.quad	.Lfunc_begin1           # DW_AT_low_pc
+	.long	.Lfunc_end1-.Lfunc_begin1 # DW_AT_high_pc
+	.byte	1                       # DW_AT_frame_base
+	.byte	81
+                                        # DW_AT_GNU_all_call_sites
+	.long	.Linfo_string5          # DW_AT_name
+	.byte	1                       # DW_AT_decl_file
+	.byte	7                       # DW_AT_decl_line
+                                        # DW_AT_prototyped
+	.long	184                     # DW_AT_type
+                                        # DW_AT_external
+	.byte	3                       # Abbrev [3] 0xa8:0xf DW_TAG_formal_parameter
+	.long	.Ldebug_loc3            # DW_AT_location
+	.long	.Linfo_string6          # DW_AT_name
+	.byte	1                       # DW_AT_decl_file
+	.byte	7                       # DW_AT_decl_line
+	.long	184                     # DW_AT_type
+	.byte	0                       # End Of Children Mark
+	.byte	6                       # Abbrev [6] 0xb8:0x7 DW_TAG_base_type
+	.long	.Linfo_string4          # DW_AT_name
+	.byte	5                       # DW_AT_encoding
+	.byte	4                       # DW_AT_byte_size
+	.byte	0                       # End Of Children Mark
+.Ldebug_info_end0:
+	.ident	"clang version 10.0.0 (git at github.com:llvm/llvm-project.git e73f78acd34360f7450b81167d9dc858ccddc262)"
+	.section	".note.GNU-stack","", at progbits
+	.addrsig
+	.section	.debug_line,"", at progbits
+.Lline_table_start0:

diff  --git a/llvm/tools/llvm-objdump/llvm-objdump.cpp b/llvm/tools/llvm-objdump/llvm-objdump.cpp
index 81b3aac5c931..7d282074efa6 100644
--- a/llvm/tools/llvm-objdump/llvm-objdump.cpp
+++ b/llvm/tools/llvm-objdump/llvm-objdump.cpp
@@ -21,7 +21,9 @@
 #include "MachODump.h"
 #include "WasmDump.h"
 #include "XCOFFDump.h"
+#include "llvm/ADT/IndexedMap.h"
 #include "llvm/ADT/Optional.h"
+#include "llvm/ADT/SmallSet.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SetOperations.h"
 #include "llvm/ADT/StringExtras.h"
@@ -79,6 +81,8 @@ using namespace llvm;
 using namespace llvm::object;
 using namespace llvm::objdump;
 
+#define DEBUG_TYPE "objdump"
+
 static cl::OptionCategory ObjdumpCat("llvm-objdump Options");
 
 static cl::opt<uint64_t> AdjustVMA(
@@ -344,6 +348,28 @@ static cl::opt<bool>
          cl::cat(ObjdumpCat));
 static cl::alias WideShort("w", cl::Grouping, cl::aliasopt(Wide));
 
+enum DebugVarsFormat {
+  DVDisabled,
+  DVUnicode,
+  DVASCII,
+};
+
+static cl::opt<DebugVarsFormat> DbgVariables(
+    "debug-vars", cl::init(DVDisabled),
+    cl::desc("Print the locations (in registers or memory) of "
+             "source-level variables alongside disassembly"),
+    cl::ValueOptional,
+    cl::values(clEnumValN(DVUnicode, "", "unicode"),
+               clEnumValN(DVUnicode, "unicode", "unicode"),
+               clEnumValN(DVASCII, "ascii", "unicode")),
+    cl::cat(ObjdumpCat));
+
+static cl::opt<int>
+    DbgIndent("debug-vars-indent", cl::init(40),
+              cl::desc("Distance to indent the source-level variable display, "
+                       "relative to the start of the disassembly"),
+              cl::cat(ObjdumpCat));
+
 static cl::extrahelp
     HelpResponse("\nPass @FILE as argument to read options from FILE.\n");
 
@@ -548,6 +574,357 @@ static bool getHidden(RelocationRef RelRef) {
 }
 
 namespace {
+
+/// Get the column at which we want to start printing the instruction
+/// disassembly, taking into account anything which appears to the left of it.
+unsigned getInstStartColumn(const MCSubtargetInfo &STI) {
+  return NoShowRawInsn ? 16 : STI.getTargetTriple().isX86() ? 40 : 24;
+}
+
+/// Stores a single expression representing the location of a source-level
+/// variable, along with the PC range for which that expression is valid.
+struct LiveVariable {
+  DWARFLocationExpression LocExpr;
+  const char *VarName;
+  DWARFUnit *Unit;
+  const DWARFDie FuncDie;
+
+  LiveVariable(const DWARFLocationExpression &LocExpr, const char *VarName,
+               DWARFUnit *Unit, const DWARFDie FuncDie)
+      : LocExpr(LocExpr), VarName(VarName), Unit(Unit), FuncDie(FuncDie) {}
+
+  bool liveAtAddress(object::SectionedAddress Addr) {
+    if (LocExpr.Range == None)
+      return false;
+    return LocExpr.Range->SectionIndex == Addr.SectionIndex &&
+           LocExpr.Range->LowPC <= Addr.Address &&
+           LocExpr.Range->HighPC > Addr.Address;
+  }
+
+  void print(raw_ostream &OS, const MCRegisterInfo &MRI) const {
+    DataExtractor Data({LocExpr.Expr.data(), LocExpr.Expr.size()},
+                       Unit->getContext().isLittleEndian(), 0);
+    DWARFExpression Expression(Data, Unit->getAddressByteSize());
+    Expression.printCompact(OS, MRI);
+  }
+};
+
+/// Helper class for printing source variable locations alongside disassembly.
+class LiveVariablePrinter {
+  // Information we want to track about one column in which we are printing a
+  // variable live range.
+  struct Column {
+    unsigned VarIdx = NullVarIdx;
+    bool LiveIn = false;
+    bool LiveOut = false;
+    bool MustDrawLabel  = false;
+
+    bool isActive() const { return VarIdx != NullVarIdx; }
+
+    static constexpr unsigned NullVarIdx = std::numeric_limits<unsigned>::max();
+  };
+
+  // All live variables we know about in the object/image file.
+  std::vector<LiveVariable> LiveVariables;
+
+  // The columns we are currently drawing.
+  IndexedMap<Column> ActiveCols;
+
+  const MCRegisterInfo &MRI;
+  const MCSubtargetInfo &STI;
+
+  void addVariable(DWARFDie FuncDie, DWARFDie VarDie) {
+    uint64_t FuncLowPC, FuncHighPC, SectionIndex;
+    FuncDie.getLowAndHighPC(FuncLowPC, FuncHighPC, SectionIndex);
+    const char *VarName = VarDie.getName(DINameKind::ShortName);
+    DWARFUnit *U = VarDie.getDwarfUnit();
+
+    Expected<DWARFLocationExpressionsVector> Locs =
+        VarDie.getLocations(dwarf::DW_AT_location);
+    if (!Locs) {
+      // If the variable doesn't have any locations, just ignore it. We don't
+      // report an error or warning here as that could be noisy on optimised
+      // code.
+      consumeError(Locs.takeError());
+      return;
+    }
+
+    for (const DWARFLocationExpression &LocExpr : *Locs) {
+      if (LocExpr.Range) {
+        LiveVariables.emplace_back(LocExpr, VarName, U, FuncDie);
+      } else {
+        // If the LocExpr does not have an associated range, it is valid for
+        // the whole of the function.
+        // TODO: technically it is not valid for any range covered by another
+        // LocExpr, does that happen in reality?
+        DWARFLocationExpression WholeFuncExpr{
+            DWARFAddressRange(FuncLowPC, FuncHighPC, SectionIndex),
+            LocExpr.Expr};
+        LiveVariables.emplace_back(WholeFuncExpr, VarName, U, FuncDie);
+      }
+    }
+  }
+
+  void addFunction(DWARFDie D) {
+    for (const DWARFDie &Child : D.children()) {
+      if (Child.getTag() == dwarf::DW_TAG_variable ||
+          Child.getTag() == dwarf::DW_TAG_formal_parameter)
+        addVariable(D, Child);
+      else
+        addFunction(Child);
+    }
+  }
+
+  // Get the column number (in characters) at which the first live variable
+  // line should be printed.
+  unsigned getIndentLevel() const {
+    return DbgIndent + getInstStartColumn(STI);
+  }
+
+  // Indent to the first live-range column to the right of the currently
+  // printed line, and return the index of that column.
+  // TODO: formatted_raw_ostream uses "column" to mean a number of characters
+  // since the last \n, and we use it to mean the number of slots in which we
+  // put live variable lines. Pick a less overloaded word.
+  unsigned moveToFirstVarColumn(formatted_raw_ostream &OS) {
+    // Logical column number: column zero is the first column we print in, each
+    // logical column is 2 physical columns wide.
+    unsigned FirstUnprintedLogicalColumn =
+        std::max((int)(OS.getColumn() - getIndentLevel() + 1) / 2, 0);
+    // Physical column number: the actual column number in characters, with
+    // zero being the left-most side of the screen.
+    unsigned FirstUnprintedPhysicalColumn =
+        getIndentLevel() + FirstUnprintedLogicalColumn * 2;
+
+    if (FirstUnprintedPhysicalColumn > OS.getColumn())
+      OS.PadToColumn(FirstUnprintedPhysicalColumn);
+
+    return FirstUnprintedLogicalColumn;
+  }
+
+  unsigned findFreeColumn() {
+    for (unsigned ColIdx = 0; ColIdx < ActiveCols.size(); ++ColIdx)
+      if (!ActiveCols[ColIdx].isActive())
+        return ColIdx;
+
+    size_t OldSize = ActiveCols.size();
+    ActiveCols.grow(std::max<size_t>(OldSize * 2, 1));
+    return OldSize;
+  }
+
+public:
+  LiveVariablePrinter(const MCRegisterInfo &MRI, const MCSubtargetInfo &STI)
+      : LiveVariables(), ActiveCols(Column()), MRI(MRI), STI(STI) {}
+
+  void dump() const {
+    for (const LiveVariable &LV : LiveVariables) {
+      dbgs() << LV.VarName << " @ " << LV.LocExpr.Range << ": ";
+      LV.print(dbgs(), MRI);
+      dbgs() << "\n";
+    }
+  }
+
+  void addCompileUnit(DWARFDie D) {
+    if (D.getTag() == dwarf::DW_TAG_subprogram)
+      addFunction(D);
+    else
+      for (const DWARFDie &Child : D.children())
+        addFunction(Child);
+  }
+
+  /// Update to match the state of the instruction between ThisAddr and
+  /// NextAddr. In the common case, any live range active at ThisAddr is
+  /// live-in to the instruction, and any live range active at NextAddr is
+  /// live-out of the instruction. If IncludeDefinedVars is false, then live
+  /// ranges starting at NextAddr will be ignored.
+  void update(object::SectionedAddress ThisAddr,
+              object::SectionedAddress NextAddr, bool IncludeDefinedVars) {
+    // First, check variables which have already been assigned a column, so
+    // that we don't change their order.
+    SmallSet<unsigned, 8> CheckedVarIdxs;
+    for (unsigned ColIdx = 0, End = ActiveCols.size(); ColIdx < End; ++ColIdx) {
+      if (!ActiveCols[ColIdx].isActive())
+        continue;
+      CheckedVarIdxs.insert(ActiveCols[ColIdx].VarIdx);
+      LiveVariable &LV = LiveVariables[ActiveCols[ColIdx].VarIdx];
+      ActiveCols[ColIdx].LiveIn = LV.liveAtAddress(ThisAddr);
+      ActiveCols[ColIdx].LiveOut = LV.liveAtAddress(NextAddr);
+      LLVM_DEBUG(dbgs() << "pass 1, " << ThisAddr.Address << "-"
+                        << NextAddr.Address << ", " << LV.VarName << ", Col "
+                        << ColIdx << ": LiveIn=" << ActiveCols[ColIdx].LiveIn
+                        << ", LiveOut=" << ActiveCols[ColIdx].LiveOut << "\n");
+
+      if (!ActiveCols[ColIdx].LiveIn && !ActiveCols[ColIdx].LiveOut)
+        ActiveCols[ColIdx].VarIdx = Column::NullVarIdx;
+    }
+
+    // Next, look for variables which don't already have a column, but which
+    // are now live.
+    if (IncludeDefinedVars) {
+      for (unsigned VarIdx = 0, End = LiveVariables.size(); VarIdx < End;
+           ++VarIdx) {
+        if (CheckedVarIdxs.count(VarIdx))
+          continue;
+        LiveVariable &LV = LiveVariables[VarIdx];
+        bool LiveIn = LV.liveAtAddress(ThisAddr);
+        bool LiveOut = LV.liveAtAddress(NextAddr);
+        if (!LiveIn && !LiveOut)
+          continue;
+
+        unsigned ColIdx = findFreeColumn();
+        LLVM_DEBUG(dbgs() << "pass 2, " << ThisAddr.Address << "-"
+                          << NextAddr.Address << ", " << LV.VarName << ", Col "
+                          << ColIdx << ": LiveIn=" << LiveIn
+                          << ", LiveOut=" << LiveOut << "\n");
+        ActiveCols[ColIdx].VarIdx = VarIdx;
+        ActiveCols[ColIdx].LiveIn = LiveIn;
+        ActiveCols[ColIdx].LiveOut = LiveOut;
+        ActiveCols[ColIdx].MustDrawLabel = true;
+      }
+    }
+  }
+
+  enum class LineChar {
+    RangeStart,
+    RangeMid,
+    RangeEnd,
+    LabelVert,
+    LabelCornerNew,
+    LabelCornerActive,
+    LabelHoriz,
+  };
+  const char *getLineChar(LineChar C) const {
+    bool IsASCII = DbgVariables == DVASCII;
+    switch (C) {
+    case LineChar::RangeStart:
+      return IsASCII ? "^" : u8"\u2548";
+    case LineChar::RangeMid:
+      return IsASCII ? "|" : u8"\u2503";
+    case LineChar::RangeEnd:
+      return IsASCII ? "v" : u8"\u253b";
+    case LineChar::LabelVert:
+      return IsASCII ? "|" : u8"\u2502";
+    case LineChar::LabelCornerNew:
+      return IsASCII ? "/" : u8"\u250c";
+    case LineChar::LabelCornerActive:
+      return IsASCII ? "|" : u8"\u2520";
+    case LineChar::LabelHoriz:
+      return IsASCII ? "-" : u8"\u2500";
+    }
+  }
+
+  /// Print live ranges to the right of an existing line. This assumes the
+  /// line is not an instruction, so doesn't start or end any live ranges, so
+  /// we only need to print active ranges or empty columns. If AfterInst is
+  /// true, this is being printed after the last instruction fed to update(),
+  /// otherwise this is being printed before it.
+  void printAfterOtherLine(formatted_raw_ostream &OS, bool AfterInst) {
+    if (ActiveCols.size()) {
+      unsigned FirstUnprintedColumn = moveToFirstVarColumn(OS);
+      for (size_t ColIdx = FirstUnprintedColumn, End = ActiveCols.size();
+           ColIdx < End; ++ColIdx) {
+        if (ActiveCols[ColIdx].isActive()) {
+          if ((AfterInst && ActiveCols[ColIdx].LiveOut) ||
+              (!AfterInst && ActiveCols[ColIdx].LiveIn))
+            OS << getLineChar(LineChar::RangeMid);
+          else if (!AfterInst && ActiveCols[ColIdx].LiveOut)
+            OS << getLineChar(LineChar::LabelVert);
+          else
+            OS << " ";
+        }
+        OS << " ";
+      }
+    }
+    OS << "\n";
+  }
+
+  /// Print any live variable range info needed to the right of a
+  /// non-instruction line of disassembly. This is where we print the variable
+  /// names and expressions, with thin line-drawing characters connecting them
+  /// to the live range which starts at the next instruction. If MustPrint is
+  /// true, we have to print at least one line (with the continuation of any
+  /// already-active live ranges) because something has already been printed
+  /// earlier on this line.
+  void printBetweenInsts(formatted_raw_ostream &OS, bool MustPrint) {
+    bool PrintedSomething = false;
+    for (unsigned ColIdx = 0, End = ActiveCols.size(); ColIdx < End; ++ColIdx) {
+      if (ActiveCols[ColIdx].isActive() && ActiveCols[ColIdx].MustDrawLabel) {
+        // First we need to print the live range markers for any active
+        // columns to the left of this one.
+        OS.PadToColumn(getIndentLevel());
+        for (unsigned ColIdx2 = 0; ColIdx2 < ColIdx; ++ColIdx2) {
+          if (ActiveCols[ColIdx2].isActive()) {
+            if (ActiveCols[ColIdx2].MustDrawLabel &&
+                           !ActiveCols[ColIdx2].LiveIn)
+              OS << getLineChar(LineChar::LabelVert) << " ";
+            else
+              OS << getLineChar(LineChar::RangeMid) << " ";
+          } else
+            OS << "  ";
+        }
+
+        // Then print the variable name and location of the new live range,
+        // with box drawing characters joining it to the live range line.
+        OS << getLineChar(ActiveCols[ColIdx].LiveIn
+                              ? LineChar::LabelCornerActive
+                              : LineChar::LabelCornerNew)
+           << getLineChar(LineChar::LabelHoriz) << " ";
+        WithColor(OS, raw_ostream::GREEN)
+            << LiveVariables[ActiveCols[ColIdx].VarIdx].VarName;
+        OS << " = ";
+        {
+          WithColor ExprColor(OS, raw_ostream::CYAN);
+          LiveVariables[ActiveCols[ColIdx].VarIdx].print(OS, MRI);
+        }
+
+        // If there are any columns to the right of the expression we just
+        // printed, then continue their live range lines.
+        unsigned FirstUnprintedColumn = moveToFirstVarColumn(OS);
+        for (unsigned ColIdx2 = FirstUnprintedColumn, End = ActiveCols.size();
+             ColIdx2 < End; ++ColIdx2) {
+          if (ActiveCols[ColIdx2].isActive() && ActiveCols[ColIdx2].LiveIn)
+            OS << getLineChar(LineChar::RangeMid) << " ";
+          else
+            OS << "  ";
+        }
+
+        OS << "\n";
+        PrintedSomething = true;
+      }
+    }
+
+    for (unsigned ColIdx = 0, End = ActiveCols.size(); ColIdx < End; ++ColIdx)
+      if (ActiveCols[ColIdx].isActive())
+        ActiveCols[ColIdx].MustDrawLabel = false;
+
+    // If we must print something (because we printed a line/column number),
+    // but don't have any new variables to print, then print a line which
+    // just continues any existing live ranges.
+    if (MustPrint && !PrintedSomething)
+      printAfterOtherLine(OS, false);
+  }
+
+  /// Print the live variable ranges to the right of a disassembled instruction.
+  void printAfterInst(formatted_raw_ostream &OS) {
+    if (!ActiveCols.size())
+      return;
+    unsigned FirstUnprintedColumn = moveToFirstVarColumn(OS);
+    for (unsigned ColIdx = FirstUnprintedColumn, End = ActiveCols.size();
+         ColIdx < End; ++ColIdx) {
+      if (!ActiveCols[ColIdx].isActive())
+        OS << "  ";
+      else if (ActiveCols[ColIdx].LiveIn && ActiveCols[ColIdx].LiveOut)
+        OS << getLineChar(LineChar::RangeMid) << " ";
+      else if (ActiveCols[ColIdx].LiveOut)
+        OS << getLineChar(LineChar::RangeStart) << " ";
+      else if (ActiveCols[ColIdx].LiveIn)
+        OS << getLineChar(LineChar::RangeEnd) << " ";
+      else
+        llvm_unreachable("var must be live in or out!");
+    }
+  }
+};
+
 class SourcePrinter {
 protected:
   DILineInfo OldLineInfo;
@@ -565,11 +942,12 @@ class SourcePrinter {
 private:
   bool cacheSource(const DILineInfo& LineInfoFile);
 
-  void printLines(raw_ostream &OS, const DILineInfo &LineInfo,
-                  StringRef Delimiter);
+  void printLines(formatted_raw_ostream &OS, const DILineInfo &LineInfo,
+                  StringRef Delimiter, LiveVariablePrinter &LVP);
 
-  void printSources(raw_ostream &OS, const DILineInfo &LineInfo,
-                    StringRef ObjectFilename, StringRef Delimiter);
+  void printSources(formatted_raw_ostream &OS, const DILineInfo &LineInfo,
+                    StringRef ObjectFilename, StringRef Delimiter,
+                    LiveVariablePrinter &LVP);
 
 public:
   SourcePrinter() = default;
@@ -583,9 +961,10 @@ class SourcePrinter {
     Symbolizer.reset(new symbolize::LLVMSymbolizer(SymbolizerOpts));
   }
   virtual ~SourcePrinter() = default;
-  virtual void printSourceLine(raw_ostream &OS,
+  virtual void printSourceLine(formatted_raw_ostream &OS,
                                object::SectionedAddress Address,
                                StringRef ObjectFilename,
+                               LiveVariablePrinter &LVP,
                                StringRef Delimiter = "; ");
 };
 
@@ -619,9 +998,10 @@ bool SourcePrinter::cacheSource(const DILineInfo &LineInfo) {
   return true;
 }
 
-void SourcePrinter::printSourceLine(raw_ostream &OS,
+void SourcePrinter::printSourceLine(formatted_raw_ostream &OS,
                                     object::SectionedAddress Address,
                                     StringRef ObjectFilename,
+                                    LiveVariablePrinter &LVP,
                                     StringRef Delimiter) {
   if (!Symbolizer)
     return;
@@ -646,14 +1026,15 @@ void SourcePrinter::printSourceLine(raw_ostream &OS,
   }
 
   if (PrintLines)
-    printLines(OS, LineInfo, Delimiter);
+    printLines(OS, LineInfo, Delimiter, LVP);
   if (PrintSource)
-    printSources(OS, LineInfo, ObjectFilename, Delimiter);
+    printSources(OS, LineInfo, ObjectFilename, Delimiter, LVP);
   OldLineInfo = LineInfo;
 }
 
-void SourcePrinter::printLines(raw_ostream &OS, const DILineInfo &LineInfo,
-                               StringRef Delimiter) {
+void SourcePrinter::printLines(formatted_raw_ostream &OS,
+                               const DILineInfo &LineInfo, StringRef Delimiter,
+                               LiveVariablePrinter &LVP) {
   bool PrintFunctionName = LineInfo.FunctionName != DILineInfo::BadString &&
                            LineInfo.FunctionName != OldLineInfo.FunctionName;
   if (PrintFunctionName) {
@@ -666,13 +1047,16 @@ void SourcePrinter::printLines(raw_ostream &OS, const DILineInfo &LineInfo,
   }
   if (LineInfo.FileName != DILineInfo::BadString && LineInfo.Line != 0 &&
       (OldLineInfo.Line != LineInfo.Line ||
-       OldLineInfo.FileName != LineInfo.FileName || PrintFunctionName))
-    OS << Delimiter << LineInfo.FileName << ":" << LineInfo.Line << "\n";
+       OldLineInfo.FileName != LineInfo.FileName || PrintFunctionName)) {
+    OS << Delimiter << LineInfo.FileName << ":" << LineInfo.Line;
+    LVP.printBetweenInsts(OS, true);
+  }
 }
 
-void SourcePrinter::printSources(raw_ostream &OS, const DILineInfo &LineInfo,
-                                 StringRef ObjectFilename,
-                                 StringRef Delimiter) {
+void SourcePrinter::printSources(formatted_raw_ostream &OS,
+                                 const DILineInfo &LineInfo,
+                                 StringRef ObjectFilename, StringRef Delimiter,
+                                 LiveVariablePrinter &LVP) {
   if (LineInfo.FileName == DILineInfo::BadString || LineInfo.Line == 0 ||
       (OldLineInfo.Line == LineInfo.Line &&
        OldLineInfo.FileName == LineInfo.FileName))
@@ -692,7 +1076,8 @@ void SourcePrinter::printSources(raw_ostream &OS, const DILineInfo &LineInfo,
       return;
     }
     // Vector begins at 0, line numbers are non-zero
-    OS << Delimiter << LineBuffer->second[LineInfo.Line - 1] << '\n';
+    OS << Delimiter << LineBuffer->second[LineInfo.Line - 1];
+    LVP.printBetweenInsts(OS, true);
   }
 }
 
@@ -710,28 +1095,30 @@ static bool hasMappingSymbols(const ObjectFile *Obj) {
   return isArmElf(Obj) || isAArch64Elf(Obj);
 }
 
-static void printRelocation(StringRef FileName, const RelocationRef &Rel,
-                            uint64_t Address, bool Is64Bits) {
+static void printRelocation(formatted_raw_ostream &OS, StringRef FileName,
+                            const RelocationRef &Rel, uint64_t Address,
+                            bool Is64Bits) {
   StringRef Fmt = Is64Bits ? "\t\t%016" PRIx64 ":  " : "\t\t\t%08" PRIx64 ":  ";
   SmallString<16> Name;
   SmallString<32> Val;
   Rel.getTypeName(Name);
   if (Error E = getRelocationValueString(Rel, Val))
     reportError(std::move(E), FileName);
-  outs() << format(Fmt.data(), Address) << Name << "\t" << Val << "\n";
+  OS << format(Fmt.data(), Address) << Name << "\t" << Val;
 }
 
 class PrettyPrinter {
 public:
   virtual ~PrettyPrinter() = default;
-  virtual void printInst(MCInstPrinter &IP, const MCInst *MI,
-                         ArrayRef<uint8_t> Bytes,
-                         object::SectionedAddress Address, raw_ostream &OS,
-                         StringRef Annot, MCSubtargetInfo const &STI,
-                         SourcePrinter *SP, StringRef ObjectFilename,
-                         std::vector<RelocationRef> *Rels = nullptr) {
+  virtual void
+  printInst(MCInstPrinter &IP, const MCInst *MI, ArrayRef<uint8_t> Bytes,
+            object::SectionedAddress Address, formatted_raw_ostream &OS,
+            StringRef Annot, MCSubtargetInfo const &STI, SourcePrinter *SP,
+            StringRef ObjectFilename, std::vector<RelocationRef> *Rels,
+            LiveVariablePrinter &LVP) {
     if (SP && (PrintSource || PrintLines))
-      SP->printSourceLine(OS, Address, ObjectFilename);
+      SP->printSourceLine(OS, Address, ObjectFilename, LVP);
+    LVP.printBetweenInsts(OS, false);
 
     size_t Start = OS.tell();
     if (!NoLeadingAddr)
@@ -741,11 +1128,9 @@ class PrettyPrinter {
       dumpBytes(Bytes, OS);
     }
 
-    // The output of printInst starts with a tab. Print some spaces so that the
-    // tab has 1 column and advances to the target tab stop. Give more columns
-    // to x86 which may encode an instruction with many bytes.
-    unsigned TabStop =
-        NoShowRawInsn ? 16 : STI.getTargetTriple().isX86() ? 40 : 24;
+    // The output of printInst starts with a tab. Print some spaces so that
+    // the tab has 1 column and advances to the target tab stop.
+    unsigned TabStop = getInstStartColumn(STI);
     unsigned Column = OS.tell() - Start;
     OS.indent(Column < TabStop - 1 ? TabStop - 1 - Column : 7 - Column % 8);
 
@@ -766,7 +1151,7 @@ PrettyPrinter PrettyPrinterInst;
 class HexagonPrettyPrinter : public PrettyPrinter {
 public:
   void printLead(ArrayRef<uint8_t> Bytes, uint64_t Address,
-                 raw_ostream &OS) {
+                 formatted_raw_ostream &OS) {
     uint32_t opcode =
       (Bytes[3] << 24) | (Bytes[2] << 16) | (Bytes[1] << 8) | Bytes[0];
     if (!NoLeadingAddr)
@@ -778,12 +1163,12 @@ class HexagonPrettyPrinter : public PrettyPrinter {
     }
   }
   void printInst(MCInstPrinter &IP, const MCInst *MI, ArrayRef<uint8_t> Bytes,
-                 object::SectionedAddress Address, raw_ostream &OS,
+                 object::SectionedAddress Address, formatted_raw_ostream &OS,
                  StringRef Annot, MCSubtargetInfo const &STI, SourcePrinter *SP,
-                 StringRef ObjectFilename,
-                 std::vector<RelocationRef> *Rels) override {
+                 StringRef ObjectFilename, std::vector<RelocationRef> *Rels,
+                 LiveVariablePrinter &LVP) override {
     if (SP && (PrintSource || PrintLines))
-      SP->printSourceLine(OS, Address, ObjectFilename, "");
+      SP->printSourceLine(OS, Address, ObjectFilename, LVP, "");
     if (!MI) {
       printLead(Bytes, Address.Address, OS);
       OS << " <unknown>";
@@ -809,7 +1194,7 @@ class HexagonPrettyPrinter : public PrettyPrinter {
     auto PrintReloc = [&]() -> void {
       while ((RelCur != RelEnd) && (RelCur->getOffset() <= Address.Address)) {
         if (RelCur->getOffset() == Address.Address) {
-          printRelocation(ObjectFilename, *RelCur, Address.Address, false);
+          printRelocation(OS, ObjectFilename, *RelCur, Address.Address, false);
           return;
         }
         ++RelCur;
@@ -820,7 +1205,7 @@ class HexagonPrettyPrinter : public PrettyPrinter {
       OS << Separator;
       Separator = "\n";
       if (SP && (PrintSource || PrintLines))
-        SP->printSourceLine(OS, Address, ObjectFilename, "");
+        SP->printSourceLine(OS, Address, ObjectFilename, LVP, "");
       printLead(Bytes, Address.Address, OS);
       OS << Preamble;
       Preamble = "   ";
@@ -848,12 +1233,12 @@ HexagonPrettyPrinter HexagonPrettyPrinterInst;
 class AMDGCNPrettyPrinter : public PrettyPrinter {
 public:
   void printInst(MCInstPrinter &IP, const MCInst *MI, ArrayRef<uint8_t> Bytes,
-                 object::SectionedAddress Address, raw_ostream &OS,
+                 object::SectionedAddress Address, formatted_raw_ostream &OS,
                  StringRef Annot, MCSubtargetInfo const &STI, SourcePrinter *SP,
-                 StringRef ObjectFilename,
-                 std::vector<RelocationRef> *Rels) override {
+                 StringRef ObjectFilename, std::vector<RelocationRef> *Rels,
+                 LiveVariablePrinter &LVP) override {
     if (SP && (PrintSource || PrintLines))
-      SP->printSourceLine(OS, Address, ObjectFilename);
+      SP->printSourceLine(OS, Address, ObjectFilename, LVP);
 
     if (MI) {
       SmallString<40> InstStr;
@@ -900,12 +1285,12 @@ AMDGCNPrettyPrinter AMDGCNPrettyPrinterInst;
 class BPFPrettyPrinter : public PrettyPrinter {
 public:
   void printInst(MCInstPrinter &IP, const MCInst *MI, ArrayRef<uint8_t> Bytes,
-                 object::SectionedAddress Address, raw_ostream &OS,
+                 object::SectionedAddress Address, formatted_raw_ostream &OS,
                  StringRef Annot, MCSubtargetInfo const &STI, SourcePrinter *SP,
-                 StringRef ObjectFilename,
-                 std::vector<RelocationRef> *Rels) override {
+                 StringRef ObjectFilename, std::vector<RelocationRef> *Rels,
+                 LiveVariablePrinter &LVP) override {
     if (SP && (PrintSource || PrintLines))
-      SP->printSourceLine(OS, Address, ObjectFilename);
+      SP->printSourceLine(OS, Address, ObjectFilename, LVP);
     if (!NoLeadingAddr)
       OS << format("%8" PRId64 ":", Address.Address / 8);
     if (!NoShowRawInsn) {
@@ -1094,26 +1479,27 @@ static char getMappingSymbolKind(ArrayRef<MappingSymbolPair> MappingSymbols,
 static uint64_t dumpARMELFData(uint64_t SectionAddr, uint64_t Index,
                                uint64_t End, const ObjectFile *Obj,
                                ArrayRef<uint8_t> Bytes,
-                               ArrayRef<MappingSymbolPair> MappingSymbols) {
+                               ArrayRef<MappingSymbolPair> MappingSymbols,
+                               raw_ostream &OS) {
   support::endianness Endian =
       Obj->isLittleEndian() ? support::little : support::big;
-  outs() << format("%8" PRIx64 ":\t", SectionAddr + Index);
+  OS << format("%8" PRIx64 ":\t", SectionAddr + Index);
   if (Index + 4 <= End) {
-    dumpBytes(Bytes.slice(Index, 4), outs());
-    outs() << "\t.word\t"
+    dumpBytes(Bytes.slice(Index, 4), OS);
+    OS << "\t.word\t"
            << format_hex(support::endian::read32(Bytes.data() + Index, Endian),
                          10);
     return 4;
   }
   if (Index + 2 <= End) {
-    dumpBytes(Bytes.slice(Index, 2), outs());
-    outs() << "\t\t.short\t"
+    dumpBytes(Bytes.slice(Index, 2), OS);
+    OS << "\t\t.short\t"
            << format_hex(support::endian::read16(Bytes.data() + Index, Endian),
                          6);
     return 2;
   }
-  dumpBytes(Bytes.slice(Index, 1), outs());
-  outs() << "\t\t.byte\t" << format_hex(Bytes[0], 4);
+  dumpBytes(Bytes.slice(Index, 1), OS);
+  OS << "\t\t.byte\t" << format_hex(Bytes[0], 4);
   return 1;
 }
 
@@ -1288,6 +1674,17 @@ static void disassembleObject(const Target *TheTarget, const ObjectFile *Obj,
     stable_sort(SecSyms.second);
   stable_sort(AbsoluteSymbols);
 
+  std::unique_ptr<DWARFContext> DICtx;
+  LiveVariablePrinter LVP(*Ctx.getRegisterInfo(), *STI);
+
+  if (DbgVariables != DVDisabled) {
+    DICtx = DWARFContext::create(*Obj);
+    for (const std::unique_ptr<DWARFUnit> &CU : DICtx->compile_units())
+      LVP.addCompileUnit(CU->getUnitDIE(false));
+  }
+
+  LLVM_DEBUG(LVP.dump());
+
   for (const SectionRef &Section : ToolSectionFilter(*Obj)) {
     if (FilterSections.empty() && !DisassembleAll &&
         (!Section.isText() || Section.isVirtual()))
@@ -1481,6 +1878,7 @@ static void disassembleObject(const Target *TheTarget, const ObjectFile *Obj,
                              Symbols[SI].Type != ELF::STT_OBJECT &&
                              !DisassembleAll;
       bool DumpARMELFData = false;
+      formatted_raw_ostream FOS(outs());
       while (Index < End) {
         // ARM and AArch64 ELF binaries can interleave data and text in the
         // same section. We rely on the markers introduced to understand what
@@ -1502,7 +1900,7 @@ static void disassembleObject(const Target *TheTarget, const ObjectFile *Obj,
 
         if (DumpARMELFData) {
           Size = dumpARMELFData(SectionAddr, Index, End, Obj, Bytes,
-                                MappingSymbols);
+                                MappingSymbols, FOS);
         } else {
           // When -z or --disassemble-zeroes are given we always dissasemble
           // them. Otherwise we might want to skip zero bytes we see.
@@ -1515,7 +1913,7 @@ static void disassembleObject(const Target *TheTarget, const ObjectFile *Obj,
 
             if (size_t N =
                     countSkippableZeroBytes(Bytes.slice(Index, MaxOffset))) {
-              outs() << "\t\t..." << '\n';
+              FOS << "\t\t..." << '\n';
               Index += N;
               continue;
             }
@@ -1530,11 +1928,14 @@ static void disassembleObject(const Target *TheTarget, const ObjectFile *Obj,
           if (Size == 0)
             Size = 1;
 
+          LVP.update({Index, Section.getIndex()},
+                     {Index + Size, Section.getIndex()}, Index + Size != End);
+
           PIP.printInst(
               *IP, Disassembled ? &Inst : nullptr, Bytes.slice(Index, Size),
-              {SectionAddr + Index + VMAAdjustment, Section.getIndex()}, outs(),
-              "", *STI, &SP, Obj->getFileName(), &Rels);
-          outs() << CommentStream.str();
+              {SectionAddr + Index + VMAAdjustment, Section.getIndex()}, FOS,
+              "", *STI, &SP, Obj->getFileName(), &Rels, LVP);
+          FOS << CommentStream.str();
           Comments.clear();
 
           // If disassembly has failed, avoid analysing invalid/incomplete
@@ -1551,7 +1952,7 @@ static void disassembleObject(const Target *TheTarget, const ObjectFile *Obj,
                           Inst, SectionAddr + Index, Size)) {
                 Target = *MaybeTarget;
                 PrintTarget = true;
-                outs() << "  # " << Twine::utohexstr(Target);
+                FOS << "  # " << Twine::utohexstr(Target);
               }
             if (PrintTarget) {
               // In a relocatable object, the target's section must reside in
@@ -1607,16 +2008,18 @@ static void disassembleObject(const Target *TheTarget, const ObjectFile *Obj,
                 if (Demangle)
                   TargetName = demangle(TargetName);
 
-                outs() << " <" << TargetName;
+                FOS << " <" << TargetName;
                 uint64_t Disp = Target - TargetAddress;
                 if (Disp)
-                  outs() << "+0x" << Twine::utohexstr(Disp);
-                outs() << '>';
+                  FOS << "+0x" << Twine::utohexstr(Disp);
+                FOS << '>';
               }
             }
           }
         }
-        outs() << "\n";
+
+        LVP.printAfterInst(FOS);
+        FOS << "\n";
 
         // Hexagon does this in pretty printer
         if (Obj->getArch() != Triple::hexagon) {
@@ -1646,8 +2049,9 @@ static void disassembleObject(const Target *TheTarget, const ObjectFile *Obj,
                 Offset += AdjustVMA;
             }
 
-            printRelocation(Obj->getFileName(), *RelCur, SectionAddr + Offset,
-                            Is64Bits);
+            printRelocation(FOS, Obj->getFileName(), *RelCur,
+                            SectionAddr + Offset, Is64Bits);
+            LVP.printAfterOtherLine(FOS, true);
             ++RelCur;
           }
         }


        


More information about the llvm-commits mailing list