]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
Objdump: Add "-M annotate" option to the AArch64 disassembler.
authorNick Clifton <nickc@redhat.com>
Fri, 8 May 2026 10:10:05 +0000 (11:10 +0100)
committerNick Clifton <nickc@redhat.com>
Fri, 8 May 2026 10:10:52 +0000 (11:10 +0100)
binutils/NEWS
binutils/doc/binutils.texi
binutils/testsuite/binutils-all/aarch64/aarch64.exp
binutils/testsuite/binutils-all/aarch64/objdumpM1.c [new file with mode: 0644]
binutils/testsuite/binutils-all/aarch64/objdumpM2.c [new file with mode: 0644]
opcodes/aarch64-dis.c

index 29821c96d0f3dfa9d4e465b9756d2d78b201496a..5532670b4a283c065cd6213788073607ffbf3660 100644 (file)
@@ -1,5 +1,9 @@
 -*- text -*-
 
+* The AArch64 disassembler now accepts a command line option of "-M annotate"
+  which displays the symbol associated with undefined instructions, should
+  there be one.
+  
 * The x86 and x86_64 disassemblers now accept a command line option of
   "-M annotate-immediates" which displays the symbol associated with immediate
   values, should there be one.
index 45df92394b69dbe900e5bbde5b54f5c9a391f894..198ae8244ef970ddb47bfc2109c11977f9bd8ab4 100644 (file)
@@ -2691,7 +2691,15 @@ compilers.
 For AArch64 targets this switch can be used to set whether instructions are
 disassembled as the most general instruction using the @option{-M no-aliases}
 option or whether instruction notes should be generated as comments in the
-disasssembly using @option{-M notes}.
+disasssembly using @option{-M notes}.  In addition the @option{-M
+annotate} option can be used to customise the handling of undefined
+instructions when disassembling executables and shared libraries.
+Normally the disassembler will just show the hexadecimal value of tge
+undefined instruction, but if annotation is enabled it will first try
+to find a symbol whose value matches the instruction's encoding.  If
+there is a match then the symbol name will be displayed instead.  This
+can be useful when disassembling non-code sections which may contain
+function and data addresses.
 
 For the x86, some of the options duplicate functions of the @option{-m}
 switch, but allow finer grained control.
index 05edcf532030cc4bd16f11800166b849667e50f5..9699df5489436ac22315baef8655c40b0bfdb82b 100644 (file)
@@ -28,3 +28,35 @@ foreach t $test_list {
     verbose [file rootname $t]
     run_dump_test [file rootname $t]
 }
+
+# Test objdump -M annotate
+
+proc test_objdump_M_annotate { } {
+    global srcdir
+    global subdir
+    global OBJDUMP
+    global OBJDUMPFLAGS
+
+    set test "objdump -M annotate"
+
+    set result [target_compile "$srcdir/$subdir/objdumpM1.c $srcdir/$subdir/objdumpM2.c" tmpdir/objdumpM executable debug]
+    if { $result != "" } {
+       unsupported "$test (build): compile result: $result"
+       return
+    }
+
+    set got [binutils_run $OBJDUMP "$OBJDUMPFLAGS -D -M annotate tmpdir/objdumpM"]
+
+    # Look for something like this in the disassembly:
+    #   420020:        00400780 .inst  0x00400780 ; [func1]
+    set want "; \[func1\]"
+
+    if [regexp $want $got] then {
+       pass $test
+       # file delete objdumpM
+    } else {
+       fail $test
+    }
+}
+
+test_objdump_M_annotate
diff --git a/binutils/testsuite/binutils-all/aarch64/objdumpM1.c b/binutils/testsuite/binutils-all/aarch64/objdumpM1.c
new file mode 100644 (file)
index 0000000..1b7c860
--- /dev/null
@@ -0,0 +1,42 @@
+int datum = 22;
+
+extern int func1 (int);
+extern int func2 (int);
+extern int func3 (int);
+extern int func4 (int);
+extern int func5 (int);
+
+/* Create an array of function pointers in the .data section.  */
+struct ptrs
+{
+  int (* fptr)(int);
+  int field;
+}
+fred [5] =
+{
+  { func1, 1 },
+  { func2, 2 },
+  { func3, 3 },
+  { func4, 4 },
+  { func5, 5 }
+};
+
+int main (int arg)
+{
+  /* FIXME: We want a way to make sure that undefined instructions that
+     are inserted via the .inst directive are not annotated.  (Since the .inst
+     directive is used explicitly for instructions and the user does not care
+     if they happen to match a symbolic value).
+     
+     Unfortunately the .inst directive only supports constant expressions so
+     we cannot use an unresolved symbolic value.  Inserting a symbolic value
+     via one of the data directives does not work since they are labeled as
+     data (via the MAP_DATA mapping state) and hence they become eligible
+     for annotation.
+
+     So for now we are stuck.  */
+
+  /* Stop the compiler from optimizing away the function pointer array
+     by using it in a non-predictable manner.  */
+  return fred[arg].fptr (fred[arg].field * datum);
+}
diff --git a/binutils/testsuite/binutils-all/aarch64/objdumpM2.c b/binutils/testsuite/binutils-all/aarch64/objdumpM2.c
new file mode 100644 (file)
index 0000000..a4e8dee
--- /dev/null
@@ -0,0 +1,5 @@
+int func1 (int arg) { return arg * 2; }
+int func2 (int arg) { return arg * 3; }
+int func3 (int arg) { return arg * 4; }
+int func4 (int arg) { return arg * 5; }
+int func5 (int arg) { return arg * 6; }
index 8544ce4b6d4b49f666dfaf102762e9a0e9d88b28..a7a170661b27714984ccb7dfad45701d893b7c6e 100644 (file)
@@ -49,6 +49,7 @@ static enum map_type last_type;
 static int last_mapping_sym = -1;
 static bfd_vma last_stop_offset = 0;
 static bfd_vma last_mapping_addr = 0;
+static bool annotate_undefined_insns = false;
 
 /* Other options */
 static int no_aliases = 0;     /* If set disassemble as most general inst.  */
@@ -91,6 +92,18 @@ parse_aarch64_dis_option (const char *option, unsigned int len ATTRIBUTE_UNUSED)
       return;
     }
 
+  if (startswith (option, "annotate"))
+    {
+      annotate_undefined_insns = true;
+      return;
+    }
+
+  if (startswith (option, "no-annotate"))
+    {
+      annotate_undefined_insns = false;
+      return;
+    }
+
 #ifdef DEBUG_AARCH64
   if (startswith (option, "debug_dump"))
     {
@@ -4260,8 +4273,24 @@ print_insn_aarch64_word (bfd_vma pc,
                                    ".inst\t");
       (*info->fprintf_styled_func) (info->stream, dis_style_immediate,
                                    "0x%08x", word);
-      (*info->fprintf_styled_func) (info->stream, dis_style_comment_start,
-                                   " ; %s", err_msg[ret]);
+      asymbol * sym = NULL;
+      /* See if this "instruction" is actually the address of something.  */
+      if (annotate_undefined_insns
+         /* Skip values that have been explicitly tagged as code.  */
+         && last_type == MAP_DATA
+         /* Skip static object files as symbol values have not be resolved yet.  */
+         && info->section != NULL
+         && info->section->owner != NULL
+         && (info->section->owner->flags & (EXEC_P | DYNAMIC)))
+       {
+         sym = info->symbol_at_address_func (word, info);
+         if (sym != NULL)
+           info->fprintf_styled_func (info->stream, dis_style_symbol,
+                                      " ; [%s]", sym->name);
+       }
+      if (sym == NULL)
+       info->fprintf_styled_func (info->stream, dis_style_comment_start,
+                                  " ; %s", err_msg[ret]);
       break;
     case ERR_OK:
       user_friendly_fixup (&inst);
@@ -4595,6 +4624,12 @@ with the -M switch (multiple options should be separated by commas):\n"));
   fprintf (stream, _("\n\
   notes            Do print instruction notes.\n"));
 
+  fprintf (stream, _("\n\
+  annotate         Display symbol names for undefined instructions.\n"));
+
+  fprintf (stream, _("\n\
+  no-annotate       Do not display symbol names for undefined instructions.\n"));
+
 #ifdef DEBUG_AARCH64
   fprintf (stream, _("\n\
   debug_dump         Temp switch for debug trace.\n"));