* [PATCH][objdump] UTF-8 jump visuzalization
2024-06-12 8:40 ` Jan Beulich
@ 2024-06-29 16:38 ` Jiří Wolker
2024-07-03 14:49 ` Jan Beulich
0 siblings, 1 reply; 5+ messages in thread
From: Jiří Wolker @ 2024-06-29 16:38 UTC (permalink / raw)
To: binutils
[-- 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
^ permalink raw reply [flat|nested] 5+ messages in thread