public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
From: "Jiří Wolker" <jwo@jwo.cz>
To: binutils@sourceware.org
Subject: [PATCH][objdump] UTF-8 jump visuzalization
Date: Sat, 29 Jun 2024 18:38:54 +0200	[thread overview]
Message-ID: <55bc9fb1-35d2-4a90-9ec8-77fe150096a6@jwo.cz> (raw)
In-Reply-To: <9e52e03c-73ab-45b3-b6db-470cc1f93dec@suse.com>

[-- Attachment #1: Type: text/plain, Size: 1063 bytes --]

I finally returned to the patch for use of box-drawing characters in the 
objdump. I attach a patch that has few bugs from the work-in-progress 
patch fixed and also contains documentation changes.

jwo

Dne 12. 06. 24 v 10:40 Jan Beulich napsal(a):
> On 12.06.2024 09:48, Jiří Wolker wrote:
>> Dne 12. 06. 24 v 9:33 Jan Beulich napsal(a):
>>> On 11.06.2024 20:14, Jiří Wolker wrote:
>>>> I've just modified the objdump to render the jump visualization using
>>>> UTF-8 characters. I attach the patch and a screenshot of the new output
>>>> with extended color enabled.
>>>>
>>>> I send this message to ask whether this feature has an opportunity to be
>>>> added to the binutils.
>>>
>>> I see no reason why it shouldn't be acceptable once finished.
>>
>> That's nice. I really like box drawing characters. :)
>>
>> I'll finish this probably in this week.
>>
>> A question: Do we want to have UTF-8 characters in binutils
>>               source code?
> 
> I see no reason why not. C99 compilers are, afaict, supposed to be dealing
> fine with them.
> 
> Jan

[-- Attachment #2: 0001-objdump-UTF-8-jump-visualization-in-disassembly.patch --]
[-- Type: text/x-patch, Size: 13295 bytes --]

From 33d751e5f5906957b74c4968ca4752fd329d1adc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ji=C5=99=C3=AD=20Wolker?= <projects@jwo.cz>
Date: Tue, 11 Jun 2024 19:56:43 +0200
Subject: [PATCH] objdump: UTF-8 jump visualization in disassembly
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

A new option ‘--visualize-jumps-lines’ was added. It uses the same
arguments like ‘--visualize-jumps’, but UTF-8 characters are used
for rendering the jump visualization instead of plain ASCII characters.

This also adds a way to customize jump visualization output using an
environment variable OBJDUMP_JUMP_LINES that contains key-value pairs
that change the strings used to print the line drawing characters.
---
 binutils/doc/binutils.texi |  41 ++++++++
 binutils/objdump.c         | 188 ++++++++++++++++++++++++++++++-------
 2 files changed, 197 insertions(+), 32 deletions(-)

diff --git a/binutils/doc/binutils.texi b/binutils/doc/binutils.texi
index c78c9e39..d68bb9b8 100644
--- a/binutils/doc/binutils.texi
+++ b/binutils/doc/binutils.texi
@@ -2321,6 +2321,7 @@ objdump [@option{-a}|@option{--archive-headers}]
         [@option{--prefix-strip=}@var{level}]
         [@option{--insn-width=}@var{width}]
         [@option{--visualize-jumps[=color|=extended-color|=off]}
+        [@option{--visualize-jumps-lines[=color|=extended-color|=off]}
         [@option{--disassembler-color=[off|terminal|on|extended]}
         [@option{-U} @var{method}] [@option{--unicode=}@var{method}]
         [@option{-V}|@option{--version}]
@@ -2883,6 +2884,46 @@ If it is necessary to disable the @option{visualize-jumps} option
 after it has previously been enabled then use
 @option{visualize-jumps=off}.
 
+Option @option{--visualize-jumps-lines} is the same, but uses box
+drawing characters instead of plain ASCII to output the
+lines. Environment variable @env{OBJDUMP_JUMP_LINES} allows
+customization of these line drawing characters. This option contains
+comma-separated key-value pairs, such as:
+
+@smallexample
+OBJDUMP_JUMP_LINES="hor=-,arrow=>"
+@end smallexample
+
+The objdump understands these keys:
+
+@table @code
+
+@item none
+White space
+
+@item hor
+Horizontal line
+
+@item ver
+Vertical line
+
+@item dest
+Arrow pointing rightwards, to the jump destination
+
+@item biarrow
+Arrow pointing right and left
+
+@item topleft
+Top left corner of the line
+
+@item branch
+Vertical line branching to the right
+
+@item bottomleft
+Bottom left corner of the line
+
+@end table
+
 @item --disassembler-color=off
 @itemx --disassembler-color=terminal
 @itemx --disassembler-color=on|color|colour
diff --git a/binutils/objdump.c b/binutils/objdump.c
index 7182abda..21200e6c 100644
--- a/binutils/objdump.c
+++ b/binutils/objdump.c
@@ -136,6 +136,7 @@ static const char * source_comment;     /* --source_comment.  */
 static bool visualize_jumps = false;	/* --visualize-jumps.  */
 static bool color_output = false;	/* --visualize-jumps=color.  */
 static bool extended_color_output = false; /* --visualize-jumps=extended-color.  */
+static bool utf8_jumps = false;         /* --visualize-jumps-utf8.  */
 static int process_links = false;       /* --process-links.  */
 static int show_all_symbols;            /* --show-all-symbols.  */
 static bool decompressed_dumps = false; /* -Z, --decompress.  */
@@ -236,6 +237,53 @@ static const struct objdump_private_desc * const objdump_private_vectors[] =
 /* The list of detected jumps inside a function.  */
 static struct jump_info *detected_jumps = NULL;
 
+/* Symbols used in the jump visualization.  */
+enum jump_line
+  {
+    jump_line_none,
+    jump_line_hor,
+    jump_line_biarrow,
+    jump_line_topleft,
+    jump_line_branch,
+    jump_line_bottomleft,
+    jump_line_dest,
+    jump_line_ver,
+  };
+static const char *const jump_line_env_tokens[] =
+  {
+    [jump_line_none] = "none",
+    [jump_line_hor] = "hor",
+    [jump_line_biarrow] = "biarrow",
+    [jump_line_topleft] = "topleft",
+    [jump_line_branch] = "branch",
+    [jump_line_bottomleft] = "bottomleft",
+    [jump_line_dest] = "dest",
+    [jump_line_ver] = "ver",
+    NULL                        /* Sentinel value. */
+  };
+static const char jump_lines[] =
+  {
+    [jump_line_none] = ' ',
+    [jump_line_hor] = '-',
+    [jump_line_biarrow] = 'X',
+    [jump_line_topleft] = ',',
+    [jump_line_branch] = '+',
+    [jump_line_bottomleft] = '\\',
+    [jump_line_dest] = '>',
+    [jump_line_ver] = '|',
+  };
+static const char *jump_lines_utf8[] =
+  {
+    [jump_line_none] = " ",
+    [jump_line_hor] = "─",
+    [jump_line_biarrow] = "X",
+    [jump_line_topleft] = "┌",
+    [jump_line_branch] = "├",
+    [jump_line_bottomleft] = "└",
+    [jump_line_dest] = "▶",
+    [jump_line_ver] = "│",
+  };
+
 typedef enum unicode_display_type
 {
   unicode_default = 0,
@@ -430,6 +478,11 @@ usage (FILE *stream, int status)
       --visualize-jumps=extended-color\n\
                                  Use extended 8-bit color codes\n"));
       fprintf (stream, _("\
+      --visualize-jumps-lines    Use box drawing characters for jumps visualization\n"));
+      fprintf (stream, _("\
+      --visualize-jumps-lines={color|extended-color}\n\
+                                 Use extended 8-bit color codes\n"));
+      fprintf (stream, _("\
       --visualize-jumps=off      Disable jump visualization\n"));
 #if DEFAULT_FOR_COLORED_DISASSEMBLY
       fprintf (stream, _("\
@@ -490,6 +543,7 @@ enum option_values
 #endif
     OPTION_SFRAME,
     OPTION_VISUALIZE_JUMPS,
+    OPTION_VISUALIZE_JUMPS_LINES,
     OPTION_DISASSEMBLER_COLOR
   };
 
@@ -559,6 +613,7 @@ static struct option long_options[]=
   {"unicode", required_argument, NULL, 'U'},
   {"version", no_argument, NULL, 'V'},
   {"visualize-jumps", optional_argument, 0, OPTION_VISUALIZE_JUMPS},
+  {"visualize-jumps-lines", optional_argument, 0, OPTION_VISUALIZE_JUMPS_LINES},
   {"wide", no_argument, NULL, 'w'},
   {"disassembler-color", required_argument, NULL, OPTION_DISASSEMBLER_COLOR},
   {NULL, no_argument, NULL, 0}
@@ -2888,14 +2943,14 @@ jump_info_sort (struct jump_info **base)
 static void
 jump_info_visualize_address (bfd_vma address,
 			     int max_level,
-			     char *line_buffer,
+			     uint8_t *line_buffer,
 			     uint8_t *color_buffer)
 {
   struct jump_info *ji = detected_jumps;
   size_t len = (max_level + 1) * 3;
 
   /* Clear line buffer.  */
-  memset (line_buffer, ' ', len);
+  memset (line_buffer, jump_line_none, len);
   memset (color_buffer, 0, len);
 
   /* Iterate over jumps and add their ASCII art.  */
@@ -2928,31 +2983,39 @@ jump_info_visualize_address (bfd_vma address,
 	      size_t i = offset + 1;
 
 	      for (; i < len - 1; ++i)
-		if (line_buffer[i] == ' ')
+		if (line_buffer[i] == jump_line_none)
 		  {
-		    line_buffer[i] = '-';
+		    line_buffer[i] = jump_line_hor;
 		    color_buffer[i] = color;
 		  }
 
-	      if (line_buffer[i] == ' ')
+	      if (line_buffer[i] == jump_line_none)
 		{
-		  line_buffer[i] = '-';
+		  line_buffer[i] = jump_line_none;
 		  color_buffer[i] = color;
 		}
-	      else if (line_buffer[i] == '>')
+	      else if (line_buffer[i] == jump_line_dest)
 		{
-		  line_buffer[i] = 'X';
+		  line_buffer[i] = jump_line_biarrow;
 		  color_buffer[i] = color;
 		}
 
-	      if (line_buffer[offset] == ' ')
+	      if (line_buffer[offset] == jump_line_none)
 		{
 		  if (address <= ji->end)
-		    line_buffer[offset] =
-		      (jump_info_min_address (ji) == address) ? ',': '+';
+		    {
+		      if (jump_info_min_address (ji) == address)
+			line_buffer[offset] = jump_line_topleft;
+		      else
+			line_buffer[offset] = jump_line_branch;
+		    }
 		  else
-		    line_buffer[offset] =
-		      (jump_info_max_address (ji) == address) ? '\'': '+';
+		    {
+		      if (jump_info_max_address (ji) == address)
+			line_buffer[offset] = jump_line_bottomleft;
+		      else
+			line_buffer[offset] = jump_line_branch;
+		    }
 		  color_buffer[offset] = color;
 		}
 	    }
@@ -2962,37 +3025,38 @@ jump_info_visualize_address (bfd_vma address,
 	      size_t i = offset + 1;
 
 	      for (; i < len - 1; ++i)
-		if (line_buffer[i] == ' ')
+		if (line_buffer[i] == jump_line_none)
 		  {
-		    line_buffer[i] = '-';
+		    line_buffer[i] = jump_line_hor;
 		    color_buffer[i] = color;
 		  }
 
-	      if (line_buffer[i] == ' ')
+	      if (line_buffer[i] == jump_line_none)
 		{
-		  line_buffer[i] = '>';
+		  line_buffer[i] = jump_line_dest;
 		  color_buffer[i] = color;
 		}
-	      else if (line_buffer[i] == '-')
+	      else if (line_buffer[i] == jump_line_hor)
 		{
-		  line_buffer[i] = 'X';
+		  line_buffer[i] = jump_line_biarrow;
 		  color_buffer[i] = color;
 		}
 
-	      if (line_buffer[offset] == ' ')
+	      if (line_buffer[offset] == jump_line_none)
 		{
 		  if (jump_info_min_address (ji) < address)
 		    line_buffer[offset] =
-		      (jump_info_max_address (ji) > address) ? '>' : '\'';
+		      (jump_info_max_address (ji) > address)
+			? jump_line_branch : jump_line_bottomleft;
 		  else
-		    line_buffer[offset] = ',';
+		    line_buffer[offset] = jump_line_topleft;
 		  color_buffer[offset] = color;
 		}
 	    }
 	  /* Draw intermediate line segment.  */
-	  else if (line_buffer[offset] == ' ')
+	  else if (line_buffer[offset] == jump_line_none)
 	    {
-	      line_buffer[offset] = '|';
+	      line_buffer[offset] = jump_line_ver;
 	      color_buffer[offset] = color;
 	    }
 	}
@@ -3221,7 +3285,8 @@ null_styled_print (const void * stream ATTRIBUTE_UNUSED,
 /* Print out jump visualization.  */
 
 static void
-print_jump_visualisation (bfd_vma addr, int max_level, char *line_buffer,
+print_jump_visualisation (bfd_vma addr, int max_level,
+			  uint8_t *line_buffer, size_t line_buffer_size,
 			  uint8_t *color_buffer)
 {
   if (!line_buffer)
@@ -3229,7 +3294,6 @@ print_jump_visualisation (bfd_vma addr, int max_level, char *line_buffer,
 
   jump_info_visualize_address (addr, max_level, line_buffer, color_buffer);
 
-  size_t line_buffer_size = strlen (line_buffer);
   char last_color = 0;
   size_t i;
 
@@ -3255,7 +3319,59 @@ print_jump_visualisation (bfd_vma addr, int max_level, char *line_buffer,
 	      last_color = color;
 	    }
 	}
-      putchar ((i < line_buffer_size) ? line_buffer[i]: ' ');
+      if (i >= line_buffer_size)
+	putchar (' ');
+      else if (utf8_jumps)
+	fputs (jump_lines_utf8[line_buffer[i]], stdout);
+      else
+	putchar (jump_lines[line_buffer[i]]);
+    }
+}
+
+static void
+process_jumps_env_var(void)
+{
+  char *var = getenv("OBJDUMP_JUMP_LINES");
+
+  if (var == NULL || var[0] == '\0')
+    {
+      return;                   /* Not set, do nothing. */
+    }
+
+  /* When set, enable the UTF-8 lines and parse the variable to allow
+     customization. */
+  utf8_jumps = true;
+
+  char *name = var;
+  for (bool last = false; !last; )
+    {
+      char *name_end = strchr(name, '=');
+      if (name_end == NULL)
+	break;
+      *name_end = '\0';
+
+      char *value = name_end + 1;
+      char *value_end = strchr(value, ',');
+      if (value_end != NULL)
+	{
+	  *value_end = '\0';
+	  name = value_end + 1;
+	}
+      else
+	{
+	  value_end = value + strlen(value);
+	  last = true;
+	}
+
+      /* Find the value name. */
+      for (size_t ind = 0; jump_line_env_tokens[ind] != NULL; ind++)
+	{
+	  if (strcmp(jump_line_env_tokens[ind], name) == 0)
+	    {
+	      jump_lines_utf8[ind] = value;
+	      break;
+	    }
+	}
     }
 }
 
@@ -3323,7 +3439,8 @@ disassemble_bytes (struct disassemble_info *inf,
 
   /* Determine maximum level. */
   uint8_t *color_buffer = NULL;
-  char *line_buffer = NULL;
+  uint8_t *line_buffer = NULL;
+  size_t line_buffer_size = -1;
   int max_level = -1;
 
   /* Some jumps were detected.  */
@@ -3340,10 +3457,11 @@ disassemble_bytes (struct disassemble_info *inf,
 
       /* Allocate buffers.  */
       size_t len = (max_level + 1) * 3 + 1;
+      line_buffer_size = len - 1;
       line_buffer = xmalloc (len);
-      line_buffer[len - 1] = 0;
+      line_buffer[line_buffer_size] = 0;
       color_buffer = xmalloc (len);
-      color_buffer[len - 1] = 0;
+      color_buffer[line_buffer_size] = 0;
     }
 
   addr_offset = start_offset;
@@ -3420,7 +3538,8 @@ disassemble_bytes (struct disassemble_info *inf,
 	    }
 
 	  print_jump_visualisation (section->vma + addr_offset,
-				    max_level, line_buffer,
+				    max_level,
+				    line_buffer, line_buffer_size,
 				    color_buffer);
 
 	  if (insns)
@@ -3629,7 +3748,8 @@ disassemble_bytes (struct disassemble_info *inf,
 		    }
 
 		  print_jump_visualisation (section->vma + j / opb,
-					    max_level, line_buffer,
+					    max_level,
+					    line_buffer, line_buffer_size,
 					    color_buffer);
 
 		  pb += octets_per_line;
@@ -6093,6 +6213,9 @@ main (int argc, char **argv)
 	case OPTION_INLINES:
 	  unwind_inlines = true;
 	  break;
+	case OPTION_VISUALIZE_JUMPS_LINES:
+	  utf8_jumps = true;
+	  /* FALLTHROUGH */
 	case OPTION_VISUALIZE_JUMPS:
 	  visualize_jumps = true;
 	  color_output = false;
@@ -6114,6 +6237,7 @@ main (int argc, char **argv)
 		  usage (stderr, 1);
 		}
 	    }
+	  process_jumps_env_var();
 	  break;
 	case OPTION_DISASSEMBLER_COLOR:
 	  if (streq (optarg, "off"))
-- 
2.44.2


  reply	other threads:[~2024-06-29 16:41 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <cb383920-d1ec-4f6c-aa79-5240e809ee52@jwo.cz>
2024-06-12  7:33 ` [PATCH WIP] objdump: " Jan Beulich
2024-06-12  7:48   ` Jiří Wolker
2024-06-12  8:40     ` Jan Beulich
2024-06-29 16:38       ` Jiří Wolker [this message]
2024-07-03 14:49         ` [PATCH][objdump] " Jan Beulich

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=55bc9fb1-35d2-4a90-9ec8-77fe150096a6@jwo.cz \
    --to=jwo@jwo.cz \
    --cc=binutils@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).