1 /* Copyright (C) 2021 Free Software Foundation, Inc.
4 This file is part of GNU Binutils.
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3, or (at your option)
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, 51 Franklin Street - Fifth Floor, Boston,
19 MA 02110-1301, USA. */
24 #include <sys/param.h>
26 #include "disassemble.h"
29 #include "dbe_types.h"
30 #include "DbeSession.h"
36 #include "StringBuilder.h"
42 uint64_t pc; // first_pc <= pc < last_pc
45 uint64_t f_offset; // file offset for first_pc
46 int codeptr[4]; // longest instruction length may not be > 16
50 static const int MAX_DISASM_STR = 2048;
51 static const int MAX_INSTR_SIZE = 8;
53 Disasm::Disasm (char *fname)
57 need_swap_endian = false;
58 my_stabs = Stabs::NewStabs (fname, fname);
62 platform = stabs->get_platform ();
66 Disasm::Disasm (Platform_t _platform, Stabs *_stabs)
70 need_swap_endian = false;
78 fprintf_func (void *arg, const char *fmt, ...)
83 int cnt = vsnprintf (buf, sizeof (buf), fmt, vp);
86 Disasm *dis = (Disasm *) arg;
87 dis->dis_str->append (buf);
92 fprintf_styled_func (void *arg, enum disassembler_style st ATTRIBUTE_UNUSED,
98 int cnt = vsnprintf (buf, sizeof (buf), fmt, vp);
101 Disasm *dis = (Disasm *) arg;
102 dis->dis_str->append (buf);
106 /* Get LENGTH bytes from info's buffer, at target address memaddr.
107 Transfer them to myaddr. */
109 read_memory_func (bfd_vma memaddr, bfd_byte *myaddr, unsigned int length,
110 disassemble_info *info)
112 unsigned int opb = info->octets_per_byte;
113 size_t end_addr_offset = length / opb;
114 size_t max_addr_offset = info->buffer_length / opb;
115 size_t octets = (memaddr - info->buffer_vma) * opb;
116 if (memaddr < info->buffer_vma
117 || memaddr - info->buffer_vma > max_addr_offset
118 || memaddr - info->buffer_vma + end_addr_offset > max_addr_offset
119 || (info->stop_vma && (memaddr >= info->stop_vma
120 || memaddr + end_addr_offset > info->stop_vma)))
122 memcpy (myaddr, info->buffer + octets, length);
127 print_address_func (bfd_vma addr, disassemble_info *info)
129 (*info->fprintf_func) (info->stream, "0x%llx", (unsigned long long) addr);
133 symbol_at_address_func (bfd_vma addr ATTRIBUTE_UNUSED,
134 disassemble_info *info ATTRIBUTE_UNUSED)
140 symbol_is_valid (asymbol * sym ATTRIBUTE_UNUSED,
141 disassemble_info *info ATTRIBUTE_UNUSED)
147 memory_error_func (int status, bfd_vma addr, disassemble_info *info)
149 info->fprintf_func (info->stream, "Address 0x%llx is out of bounds.\n",
150 (unsigned long long) addr);
154 Disasm::disasm_open ()
157 snprintf (addr_fmt, sizeof (addr_fmt), NTXT ("%s"), NTXT ("%8llx: "));
159 dis_str = new StringBuilder;
166 need_swap_endian = (DbeSession::platform == Sparc);
172 need_swap_endian = (DbeSession::platform != Sparc);
176 memset (&dis_info, 0, sizeof (dis_info));
177 dis_info.flavour = bfd_target_unknown_flavour;
178 dis_info.endian = BFD_ENDIAN_UNKNOWN;
179 dis_info.endian_code = dis_info.endian;
180 dis_info.octets_per_byte = 1;
181 dis_info.disassembler_needs_relocs = FALSE;
182 dis_info.fprintf_func = fprintf_func;
183 dis_info.fprintf_styled_func = fprintf_styled_func;
184 dis_info.stream = this;
185 dis_info.disassembler_options = NULL;
186 dis_info.read_memory_func = read_memory_func;
187 dis_info.memory_error_func = memory_error_func;
188 dis_info.print_address_func = print_address_func;
189 dis_info.symbol_at_address_func = symbol_at_address_func;
190 dis_info.symbol_is_valid = symbol_is_valid;
191 dis_info.display_endian = BFD_ENDIAN_UNKNOWN;
192 dis_info.symtab = NULL;
193 dis_info.symtab_size = 0;
194 dis_info.buffer_vma = 0;
198 dis_info.arch = bfd_arch_aarch64;
199 dis_info.mach = bfd_mach_aarch64;
203 dis_info.arch = bfd_arch_i386;
204 dis_info.mach = bfd_mach_x86_64;
210 dis_info.arch = bfd_arch_unknown;
211 dis_info.endian = BFD_ENDIAN_UNKNOWN;
214 dis_info.display_endian = dis_info.endian = BFD_ENDIAN_BIG;
215 dis_info.display_endian = dis_info.endian = BFD_ENDIAN_LITTLE;
216 dis_info.display_endian = dis_info.endian = BFD_ENDIAN_UNKNOWN;
217 disassemble_init_for_target (&dis_info);
228 Disasm::set_img_name (char *img_fname)
230 if (stabs == NULL && img_fname && dwin == NULL)
232 dwin = new Data_window (img_fname);
233 if (dwin->not_opened ())
239 dwin->need_swap_endian = need_swap_endian;
244 Disasm::remove_disasm_hndl (void *hndl)
246 DisContext *ctx = (DisContext *) hndl;
252 Disasm::get_instr_size (uint64_t vaddr, void *hndl)
254 DisContext *ctx = (DisContext *) hndl;
255 if (ctx == NULL || vaddr < ctx->first_pc || vaddr >= ctx->last_pc)
258 size_t sz = ctx->is_Intel ? sizeof (ctx->codeptr) : 4;
259 if (sz > ctx->last_pc - vaddr)
260 sz = (size_t) (ctx->last_pc - vaddr);
261 if (ctx->elf->get_data (ctx->f_offset + (vaddr - ctx->first_pc),
262 sz, ctx->codeptr) == NULL)
265 char buf[MAX_DISASM_STR];
267 uint64_t inst_vaddr = vaddr;
269 size_t instrs_cnt = 0;
270 disasm_err_code_t status = disasm (handle, &inst_vaddr, ctx->last_pc, 1,
271 ctx, buf, sizeof (buf), &instrs_cnt);
272 if (instrs_cnt != 1 || status != disasm_err_ok)
275 return (int) (inst_vaddr - vaddr);
280 Disasm::set_addr_end (uint64_t end_address)
283 int len = snprintf (buf, sizeof (buf), "%llx", (long long) end_address);
284 snprintf (addr_fmt, sizeof (addr_fmt), "%%%dllx: ", len < 8 ? 8 : len);
288 Disasm::get_disasm (uint64_t inst_address, uint64_t end_address,
289 uint64_t start_address, uint64_t f_offset, int64_t &inst_size)
292 if (inst_address >= end_address)
294 Data_window *dw = stabs ? stabs->openElf (false) : dwin;
298 unsigned char buffer[MAX_DISASM_STR];
299 dis_info.buffer = buffer;
300 dis_info.buffer_length = end_address - inst_address;
301 if (dis_info.buffer_length > sizeof (buffer))
302 dis_info.buffer_length = sizeof (buffer);
303 dw->get_data (f_offset + (inst_address - start_address),
304 dis_info.buffer_length, dis_info.buffer);
306 dis_str->setLength (0);
308 disassembler_ftype disassemble = disassembler (dis_info.arch, dis_info.endian,
309 dis_info.mach, &abfd);
310 if (disassemble == NULL)
312 printf ("ERROR: unsupported disassemble\n");
315 inst_size = disassemble (0, &dis_info);
322 sb.appendf (addr_fmt, inst_address); // Write address
324 // Write hex bytes of instruction
329 for (int i = 0; i < inst_size; i++)
331 unsigned int hex_value = buffer[i] & 0xff;
332 snprintf (bytes + 3 * i, sizeof (bytes) - 3 * i, "%02x ", hex_value);
334 const char *fmt = "%s ";
335 if (platform == Intel)
336 fmt = "%-21s "; // 21 = 3 * 7 - maximum instruction length on Intel
337 sb.appendf (fmt, bytes);
342 if (ctx.is_Intel) // longest instruction length for Intel is 7
343 sb.appendf (NTXT ("%-7s %s"), parts_array[1], parts_array[2]);
344 else // longest instruction length for SPARC is 11
345 sb.appendf (NTXT ("%-11s %s"), parts_array[1], parts_array[2]);
346 if (strcmp (parts_array[1], NTXT ("call")) == 0)
348 if (strncmp (parts_array[2], NTXT ("0x"), 2) == 0)
349 sb.append (GTXT ("\t! (Unable to determine target symbol)"));
352 return sb.toString ();
357 Disasm::get_inst_ptr (disasm_handle_t, uint64_t vaddr, void *pass_through)
359 // Actually it fetches only one instruction at a time for sparc,
360 // and one byte at a time for intel.
361 DisContext *ctx = (DisContext*) pass_through;
362 size_t sz = ctx->is_Intel ? 1 : 4;
363 if (vaddr + sz > ctx->last_pc)
365 ctx->codeptr[0] = -1;
368 if (ctx->elf->get_data (ctx->f_offset + (vaddr - ctx->first_pc), sz, ctx->codeptr) == NULL)
370 ctx->codeptr[0] = -1;
373 if (ctx->elf->need_swap_endian && !ctx->is_Intel)
374 ctx->codeptr[0] = ctx->elf->decode (ctx->codeptr[0]);
378 // get a symbol name for an address
380 Disasm::get_sym_name (disasm_handle_t, // an open disassembler handle
381 uint64_t target_address, // the target virtual address
382 uint64_t inst_address, // virtual address of instruction
383 // being disassembled
384 int use_relocation, // flag to use relocation information
385 char *buffer, // places the symbol here
386 size_t buffer_size, // limit on symbol length
387 int *, // sys/elf_{SPARC.386}.h
388 uint64_t *offset, // from the symbol to the address
389 void *pass_through) // disassembler context
391 char buf[MAXPATHLEN];
393 return disasm_err_symbol;
395 DisContext *ctxp = (DisContext*) pass_through;
399 uint64_t addr = ctxp->f_offset + (inst_address - ctxp->first_pc);
400 name = ctxp->stabs->sym_name (target_address, addr, use_relocation);
403 return disasm_err_symbol;
407 s = cplus_demangle (name, DMGL_PARAMS);
410 snprintf (buffer, buffer_size, NTXT ("%s"), s);
414 snprintf (buffer, buffer_size, NTXT ("%s"), name);
417 return disasm_err_ok;