GDB (xrefs)
scm-disasm.c
Go to the documentation of this file.
1 /* Scheme interface to architecture.
2 
3  Copyright (C) 2014-2015 Free Software Foundation, Inc.
4 
5  This file is part of GDB.
6 
7  This program is free software; you can redistribute it and/or modify
8  it under the terms of the GNU General Public License as published by
9  the Free Software Foundation; either version 3 of the License, or
10  (at your option) any later version.
11 
12  This program is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with this program. If not, see <http://www.gnu.org/licenses/>. */
19 
20 /* See README file in this directory for implementation notes, coding
21  conventions, et.al. */
22 
23 #include "defs.h"
24 #include "arch-utils.h"
25 #include "disasm.h"
26 #include "dis-asm.h"
27 #include "gdbarch.h"
28 #include "gdbcore.h" /* Why is memory_error here? */
29 #include "guile-internal.h"
30 
31 static SCM port_keyword;
32 static SCM offset_keyword;
33 static SCM size_keyword;
34 static SCM count_keyword;
35 
36 static SCM address_symbol;
37 static SCM asm_symbol;
38 static SCM length_symbol;
39 
40 /* Struct used to pass "application data" in disassemble_info. */
41 
43 {
44  struct gdbarch *gdbarch;
45  SCM port;
46  /* The offset of the address of the first instruction in PORT. */
48 };
49 
50 /* Struct used to pass data from gdbscm_disasm_read_memory to
51  gdbscm_disasm_read_memory_worker. */
52 
54 {
55  bfd_vma memaddr;
56  bfd_byte *myaddr;
57  unsigned int length;
58  struct disassemble_info *dinfo;
59 };
60 
61 /* Subroutine of gdbscm_arch_disassemble to simplify it.
62  Return the result for one instruction. */
63 
64 static SCM
65 dascm_make_insn (CORE_ADDR pc, const char *assembly, int insn_len)
66 {
67  return scm_list_3 (scm_cons (address_symbol,
69  scm_cons (asm_symbol,
70  gdbscm_scm_from_c_string (assembly)),
71  scm_cons (length_symbol,
72  scm_from_int (insn_len)));
73 }
74 
75 /* Helper function for gdbscm_disasm_read_memory to safely read from a
76  Scheme port. Called via gdbscm_call_guile.
77  The result is a statically allocated error message or NULL if success. */
78 
79 static void *
81 {
82  struct gdbscm_disasm_read_data *data = datap;
83  struct disassemble_info *dinfo = data->dinfo;
84  struct gdbscm_disasm_data *disasm_data = dinfo->application_data;
85  SCM seekto, newpos, port = disasm_data->port;
86  size_t bytes_read;
87 
88  seekto = gdbscm_scm_from_ulongest (data->memaddr - disasm_data->offset);
89  newpos = scm_seek (port, seekto, scm_from_int (SEEK_SET));
90  if (!scm_is_eq (seekto, newpos))
91  return "seek error";
92 
93  bytes_read = scm_c_read (port, data->myaddr, data->length);
94 
95  if (bytes_read != data->length)
96  return "short read";
97 
98  /* If we get here the read succeeded. */
99  return NULL;
100 }
101 
102 /* disassemble_info.read_memory_func for gdbscm_print_insn_from_port. */
103 
104 static int
105 gdbscm_disasm_read_memory (bfd_vma memaddr, bfd_byte *myaddr,
106  unsigned int length,
107  struct disassemble_info *dinfo)
108 {
109  struct gdbscm_disasm_read_data data;
110  void *status;
111 
112  data.memaddr = memaddr;
113  data.myaddr = myaddr;
114  data.length = length;
115  data.dinfo = dinfo;
116 
118 
119  /* TODO: IWBN to distinguish problems reading target memory versus problems
120  with the port (e.g., EOF).
121  We return TARGET_XFER_E_IO here as that's what memory_error looks for. */
122  return status != NULL ? TARGET_XFER_E_IO : 0;
123 }
124 
125 /* disassemble_info.memory_error_func for gdbscm_print_insn_from_port.
126  Technically speaking, we don't need our own memory_error_func,
127  but to not provide one would leave a subtle dependency in the code.
128  This function exists to keep a clear boundary. */
129 
130 static void
132  struct disassemble_info *info)
133 {
134  memory_error (status, memaddr);
135 }
136 
137 /* disassemble_info.print_address_func for gdbscm_print_insn_from_port.
138  Since we need to use our own application_data value, we need to supply
139  this routine as well. */
140 
141 static void
142 gdbscm_disasm_print_address (bfd_vma addr, struct disassemble_info *info)
143 {
144  struct gdbscm_disasm_data *data = info->application_data;
145  struct gdbarch *gdbarch = data->gdbarch;
146 
147  print_address (gdbarch, addr, info->stream);
148 }
149 
150 /* Subroutine of gdbscm_arch_disassemble to simplify it.
151  Call gdbarch_print_insn using a port for input.
152  PORT must be seekable.
153  OFFSET is the offset in PORT from which addresses begin.
154  For example, when printing from a bytevector, addresses passed to the
155  bv seek routines must be in the range [0,size). However, the bytevector
156  may represent an instruction at address 0x1234. To handle this case pass
157  0x1234 for OFFSET.
158  This is based on gdb_print_insn, see it for details. */
159 
160 static int
162  SCM port, ULONGEST offset, CORE_ADDR memaddr,
163  struct ui_file *stream, int *branch_delay_insns)
164 {
165  struct disassemble_info di;
166  int length;
167  struct gdbscm_disasm_data data;
168 
169  di = gdb_disassemble_info (gdbarch, stream);
170  data.gdbarch = gdbarch;
171  data.port = port;
172  data.offset = offset;
173  di.application_data = &data;
174  di.read_memory_func = gdbscm_disasm_read_memory;
175  di.memory_error_func = gdbscm_disasm_memory_error;
176  di.print_address_func = gdbscm_disasm_print_address;
177 
178  length = gdbarch_print_insn (gdbarch, memaddr, &di);
179 
180  if (branch_delay_insns)
181  {
182  if (di.insn_info_valid)
183  *branch_delay_insns = di.branch_delay_insns;
184  else
185  *branch_delay_insns = 0;
186  }
187 
188  return length;
189 }
190 
191 /* (arch-disassemble <gdb:arch> address
192  [#:port port] [#:offset address] [#:size integer] [#:count integer])
193  -> list
194 
195  Returns a list of disassembled instructions.
196  If PORT is provided, read bytes from it. Otherwise read target memory.
197  If PORT is #f, read target memory.
198  PORT must be seekable. IWBN to remove this restriction, and a future
199  release may. For now the restriction is in place because it's not clear
200  all disassemblers are strictly sequential.
201  If SIZE is provided, limit the number of bytes read to this amount.
202  If COUNT is provided, limit the number of instructions to this amount.
203 
204  Each instruction in the result is an alist:
205  (('address . address) ('asm . disassembly) ('length . length)).
206  We could use a hash table (dictionary) but there aren't that many fields. */
207 
208 static SCM
209 gdbscm_arch_disassemble (SCM self, SCM start_scm, SCM rest)
210 {
211  arch_smob *a_smob
212  = arscm_get_arch_smob_arg_unsafe (self, SCM_ARG1, FUNC_NAME);
213  struct gdbarch *gdbarch = arscm_get_gdbarch (a_smob);
214  const SCM keywords[] = {
216  };
217  int port_arg_pos = -1, offset_arg_pos = -1;
218  int size_arg_pos = -1, count_arg_pos = -1;
219  SCM port = SCM_BOOL_F;
220  ULONGEST offset = 0;
221  unsigned int count = 1;
222  unsigned int size;
223  ULONGEST start_arg;
224  CORE_ADDR start, end;
225  CORE_ADDR pc;
226  unsigned int i;
227  int using_port;
228  SCM result;
229 
230  gdbscm_parse_function_args (FUNC_NAME, SCM_ARG2, keywords, "U#OUuu",
231  start_scm, &start_arg, rest,
232  &port_arg_pos, &port,
233  &offset_arg_pos, &offset,
234  &size_arg_pos, &size,
235  &count_arg_pos, &count);
236  /* START is first stored in a ULONGEST because we don't have a format char
237  for CORE_ADDR, and it's not really worth it to have one yet. */
238  start = start_arg;
239 
240  if (port_arg_pos > 0)
241  {
242  SCM_ASSERT_TYPE (gdbscm_is_false (port)
243  || gdbscm_is_true (scm_input_port_p (port)),
244  port, port_arg_pos, FUNC_NAME, _("input port"));
245  }
246  using_port = gdbscm_is_true (port);
247 
248  if (offset_arg_pos > 0
249  && (port_arg_pos < 0
250  || gdbscm_is_false (port)))
251  {
252  gdbscm_out_of_range_error (FUNC_NAME, offset_arg_pos,
253  gdbscm_scm_from_ulongest (offset),
254  _("offset provided but port is missing"));
255  }
256 
257  if (size_arg_pos > 0)
258  {
259  if (size == 0)
260  return SCM_EOL;
261  /* For now be strict about start+size overflowing. If it becomes
262  a nuisance we can relax things later. */
263  if (start + size < start)
264  {
266  scm_list_2 (gdbscm_scm_from_ulongest (start),
267  gdbscm_scm_from_ulongest (size)),
268  _("start+size overflows"));
269  }
270  end = start + size - 1;
271  }
272  else
273  end = ~(CORE_ADDR) 0;
274 
275  if (count == 0)
276  return SCM_EOL;
277 
278  result = SCM_EOL;
279 
280  for (pc = start, i = 0; pc <= end && i < count; )
281  {
282  int insn_len = 0;
283  char *as = NULL;
284  struct ui_file *memfile = mem_fileopen ();
285  struct cleanup *cleanups = make_cleanup_ui_file_delete (memfile);
286 
287  TRY
288  {
289  if (using_port)
290  {
291  insn_len = gdbscm_print_insn_from_port (gdbarch, port, offset,
292  pc, memfile, NULL);
293  }
294  else
295  insn_len = gdb_print_insn (gdbarch, pc, memfile, NULL);
296  }
297  CATCH (except, RETURN_MASK_ALL)
298  {
300  }
301  END_CATCH
302 
303  as = ui_file_xstrdup (memfile, NULL);
304 
305  result = scm_cons (dascm_make_insn (pc, as, insn_len),
306  result);
307 
308  pc += insn_len;
309  i++;
310  do_cleanups (cleanups);
311  xfree (as);
312  }
313 
314  return scm_reverse_x (result, SCM_EOL);
315 }
316 
317 /* Initialize the Scheme architecture support. */
318 
319 static const scheme_function disasm_functions[] =
320 {
321  { "arch-disassemble", 2, 0, 1, gdbscm_arch_disassemble,
322  "\
323 Return list of disassembled instructions in memory.\n\
324 \n\
325  Arguments: <gdb:arch> start-address\n\
326  [#:port port] [#:offset address]\n\
327  [#:size <integer>] [#:count <integer>]\n\
328  port: If non-#f, it is an input port to read bytes from.\n\
329  offset: Specifies the address offset of the first byte in the port.\n\
330  This is useful if the input is from something other than memory\n\
331  (e.g., a bytevector) and you want the result to be as if the bytes\n\
332  came from that address. The value to pass for start-address is\n\
333  then also the desired disassembly address, not the offset in, e.g.,\n\
334  the bytevector.\n\
335  size: Limit the number of bytes read to this amount.\n\
336  count: Limit the number of instructions to this amount.\n\
337 \n\
338  Returns:\n\
339  Each instruction in the result is an alist:\n\
340  (('address . address) ('asm . disassembly) ('length . length))." },
341 
343 };
344 
345 void
347 {
348  gdbscm_define_functions (disasm_functions, 1);
349 
350  port_keyword = scm_from_latin1_keyword ("port");
351  offset_keyword = scm_from_latin1_keyword ("offset");
352  size_keyword = scm_from_latin1_keyword ("size");
353  count_keyword = scm_from_latin1_keyword ("count");
354 
355  address_symbol = scm_from_latin1_symbol ("address");
356  asm_symbol = scm_from_latin1_symbol ("asm");
357  length_symbol = scm_from_latin1_symbol ("length");
358 }
arch_smob * arscm_get_arch_smob_arg_unsafe(SCM arch_scm, int arg_pos, const char *func_name)
Definition: scm-arch.c:151
struct disassemble_info * dinfo
Definition: scm-disasm.c:58
void gdbscm_define_functions(const scheme_function *, int is_public)
Definition: scm-utils.c:44
bfd_vma CORE_ADDR
Definition: common-types.h:41
void print_address(struct gdbarch *, CORE_ADDR, struct ui_file *)
Definition: printcmd.c:741
static void * gdbscm_disasm_read_memory_worker(void *datap)
Definition: scm-disasm.c:80
SCM gdbscm_scm_from_ulongest(ULONGEST l)
Definition: scm-utils.c:552
void xfree(void *)
Definition: common-utils.c:97
static int branch_delay_insns
Definition: printcmd.c:70
char * ui_file_xstrdup(struct ui_file *file, long *length)
Definition: ui-file.c:345
static SCM length_symbol
Definition: scm-disasm.c:38
#define FUNC_NAME
struct gdbarch * arscm_get_gdbarch(arch_smob *a_smob)
Definition: scm-arch.c:88
#define _(String)
Definition: gdb_locale.h:40
#define END_CATCH
static SCM gdbscm_arch_disassemble(SCM self, SCM start_scm, SCM rest)
Definition: scm-disasm.c:209
struct gdbarch * gdbarch
Definition: scm-disasm.c:44
#define gdbscm_is_true(scm)
#define TRY
void memory_error(enum target_xfer_status err, CORE_ADDR memaddr)
Definition: corefile.c:217
static SCM count_keyword
Definition: scm-disasm.c:34
#define CATCH(EXCEPTION, MASK)
unsigned int length
Definition: scm-disasm.c:57
static SCM dascm_make_insn(CORE_ADDR pc, const char *assembly, int insn_len)
Definition: scm-disasm.c:65
SCM gdbscm_scm_from_c_string(const char *string)
Definition: scm-string.c:44
static SCM asm_symbol
Definition: scm-disasm.c:37
#define gdbscm_is_false(scm)
static int gdbscm_disasm_read_memory(bfd_vma memaddr, bfd_byte *myaddr, unsigned int length, struct disassemble_info *dinfo)
Definition: scm-disasm.c:105
mach_port_t mach_port_t name mach_port_t mach_port_t name error_t int status
Definition: gnu-nat.c:1816
int gdb_print_insn(struct gdbarch *gdbarch, CORE_ADDR memaddr, struct ui_file *stream, int *branch_delay_insns)
Definition: disasm.c:444
static void gdbscm_disasm_print_address(bfd_vma addr, struct disassemble_info *info)
Definition: scm-disasm.c:142
static SCM offset_keyword
Definition: scm-disasm.c:32
struct ui_file * mem_fileopen(void)
Definition: ui-file.c:427
#define END_FUNCTIONS
#define SEEK_SET
Definition: defs.h:87
struct cleanup * make_cleanup_ui_file_delete(struct ui_file *arg)
Definition: utils.c:237
static SCM size_keyword
Definition: scm-disasm.c:33
static SCM port_keyword
Definition: scm-disasm.c:31
void gdbscm_out_of_range_error(const char *subr, int arg_pos, SCM bad_value, const char *error) ATTRIBUTE_NORETURN
int offset
Definition: agent.c:65
void gdbscm_initialize_disasm(void)
Definition: scm-disasm.c:346
void * gdbscm_with_guile(void *(*func)(void *), void *data)
#define GDBSCM_HANDLE_GDB_EXCEPTION_WITH_CLEANUPS(exception, cleanups)
static SCM address_symbol
Definition: scm-disasm.c:36
struct disassemble_info gdb_disassemble_info(struct gdbarch *gdbarch, struct ui_file *file)
Definition: disasm.c:379
void gdbscm_parse_function_args(const char *function_name, int beginning_arg_pos, const SCM *keywords, const char *format,...)
Definition: scm-utils.c:377
unsigned long long ULONGEST
Definition: common-types.h:53
static void gdbscm_disasm_memory_error(int status, bfd_vma memaddr, struct disassemble_info *info)
Definition: scm-disasm.c:131
int gdbarch_print_insn(struct gdbarch *gdbarch, bfd_vma vma, struct disassemble_info *info)
Definition: gdbarch.c:3057
size_t size
Definition: go32-nat.c:242
void do_cleanups(struct cleanup *old_chain)
Definition: cleanups.c:175
static int gdbscm_print_insn_from_port(struct gdbarch *gdbarch, SCM port, ULONGEST offset, CORE_ADDR memaddr, struct ui_file *stream, int *branch_delay_insns)
Definition: scm-disasm.c:161