GDB (xrefs)
scm-disasm.c
Go to the documentation of this file.
1 /* Scheme interface to architecture.
2 
3  Copyright (C) 2014-2018 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 
41 {
42 public:
44  struct ui_file *stream,
45  SCM port, ULONGEST offset);
46 
47  SCM port;
48  /* The offset of the address of the first instruction in PORT. */
50 };
51 
52 /* Struct used to pass data from gdbscm_disasm_read_memory to
53  gdbscm_disasm_read_memory_worker. */
54 
56 {
57  bfd_vma memaddr;
58  bfd_byte *myaddr;
59  unsigned int length;
61 };
62 
63 /* Subroutine of gdbscm_arch_disassemble to simplify it.
64  Return the result for one instruction. */
65 
66 static SCM
67 dascm_make_insn (CORE_ADDR pc, const char *assembly, int insn_len)
68 {
69  return scm_list_3 (scm_cons (address_symbol,
71  scm_cons (asm_symbol,
72  gdbscm_scm_from_c_string (assembly)),
73  scm_cons (length_symbol,
74  scm_from_int (insn_len)));
75 }
76 
77 /* Helper function for gdbscm_disasm_read_memory to safely read from a
78  Scheme port. Called via gdbscm_call_guile.
79  The result is a statically allocated error message or NULL if success. */
80 
81 static const char *
83 {
84  struct gdbscm_disasm_read_data *data
85  = (struct gdbscm_disasm_read_data *) datap;
87  SCM seekto, newpos, port = dinfo->port;
88  size_t bytes_read;
89 
90  seekto = gdbscm_scm_from_ulongest (data->memaddr - dinfo->offset);
91  newpos = scm_seek (port, seekto, scm_from_int (SEEK_SET));
92  if (!scm_is_eq (seekto, newpos))
93  return "seek error";
94 
95  bytes_read = scm_c_read (port, data->myaddr, data->length);
96 
97  if (bytes_read != data->length)
98  return "short read";
99 
100  /* If we get here the read succeeded. */
101  return NULL;
102 }
103 
104 /* disassemble_info.read_memory_func for gdbscm_print_insn_from_port. */
105 
106 static int
108  unsigned int length,
109  struct disassemble_info *dinfo)
110 {
111  gdbscm_disassembler *self
112  = static_cast<gdbscm_disassembler *> (dinfo->application_data);
113  struct gdbscm_disasm_read_data data;
114  const char *status;
115 
116  data.memaddr = memaddr;
117  data.myaddr = myaddr;
118  data.length = length;
119  data.dinfo = self;
120 
122 
123  /* TODO: IWBN to distinguish problems reading target memory versus problems
124  with the port (e.g., EOF). */
125  return status != NULL ? -1 : 0;
126 }
127 
129  struct ui_file *stream,
130  SCM port_, ULONGEST offset_)
132  port (port_), offset (offset_)
133 {
134 }
135 
136 /* Subroutine of gdbscm_arch_disassemble to simplify it.
137  Call gdbarch_print_insn using a port for input.
138  PORT must be seekable.
139  OFFSET is the offset in PORT from which addresses begin.
140  For example, when printing from a bytevector, addresses passed to the
141  bv seek routines must be in the range [0,size). However, the bytevector
142  may represent an instruction at address 0x1234. To handle this case pass
143  0x1234 for OFFSET.
144  This is based on gdb_print_insn, see it for details. */
145 
146 static int
148  SCM port, ULONGEST offset, CORE_ADDR memaddr,
149  string_file *stream, int *branch_delay_insns)
150 {
151  gdbscm_disassembler di (gdbarch, stream, port, offset);
152 
154 }
155 
156 /* (arch-disassemble <gdb:arch> address
157  [#:port port] [#:offset address] [#:size integer] [#:count integer])
158  -> list
159 
160  Returns a list of disassembled instructions.
161  If PORT is provided, read bytes from it. Otherwise read target memory.
162  If PORT is #f, read target memory.
163  PORT must be seekable. IWBN to remove this restriction, and a future
164  release may. For now the restriction is in place because it's not clear
165  all disassemblers are strictly sequential.
166  If SIZE is provided, limit the number of bytes read to this amount.
167  If COUNT is provided, limit the number of instructions to this amount.
168 
169  Each instruction in the result is an alist:
170  (('address . address) ('asm . disassembly) ('length . length)).
171  We could use a hash table (dictionary) but there aren't that many fields. */
172 
173 static SCM
174 gdbscm_arch_disassemble (SCM self, SCM start_scm, SCM rest)
175 {
176  arch_smob *a_smob
177  = arscm_get_arch_smob_arg_unsafe (self, SCM_ARG1, FUNC_NAME);
178  struct gdbarch *gdbarch = arscm_get_gdbarch (a_smob);
179  const SCM keywords[] = {
181  };
182  int port_arg_pos = -1, offset_arg_pos = -1;
183  int size_arg_pos = -1, count_arg_pos = -1;
184  SCM port = SCM_BOOL_F;
185  ULONGEST offset = 0;
186  unsigned int count = 1;
187  unsigned int size;
188  ULONGEST start_arg;
189  CORE_ADDR start, end;
190  CORE_ADDR pc;
191  unsigned int i;
192  int using_port;
193  SCM result;
194 
195  gdbscm_parse_function_args (FUNC_NAME, SCM_ARG2, keywords, "U#OUuu",
196  start_scm, &start_arg, rest,
197  &port_arg_pos, &port,
198  &offset_arg_pos, &offset,
199  &size_arg_pos, &size,
200  &count_arg_pos, &count);
201  /* START is first stored in a ULONGEST because we don't have a format char
202  for CORE_ADDR, and it's not really worth it to have one yet. */
203  start = start_arg;
204 
205  if (port_arg_pos > 0)
206  {
207  SCM_ASSERT_TYPE (gdbscm_is_false (port)
208  || gdbscm_is_true (scm_input_port_p (port)),
209  port, port_arg_pos, FUNC_NAME, _("input port"));
210  }
211  using_port = gdbscm_is_true (port);
212 
213  if (offset_arg_pos > 0
214  && (port_arg_pos < 0
215  || gdbscm_is_false (port)))
216  {
217  gdbscm_out_of_range_error (FUNC_NAME, offset_arg_pos,
219  _("offset provided but port is missing"));
220  }
221 
222  if (size_arg_pos > 0)
223  {
224  if (size == 0)
225  return SCM_EOL;
226  /* For now be strict about start+size overflowing. If it becomes
227  a nuisance we can relax things later. */
228  if (start + size < start)
229  {
231  scm_list_2 (gdbscm_scm_from_ulongest (start),
233  _("start+size overflows"));
234  }
235  end = start + size - 1;
236  }
237  else
238  end = ~(CORE_ADDR) 0;
239 
240  if (count == 0)
241  return SCM_EOL;
242 
243  result = SCM_EOL;
244 
245  for (pc = start, i = 0; pc <= end && i < count; )
246  {
247  int insn_len = 0;
248  string_file buf;
249 
250  TRY
251  {
252  if (using_port)
253  {
254  insn_len = gdbscm_print_insn_from_port (gdbarch, port, offset,
255  pc, &buf, NULL);
256  }
257  else
258  insn_len = gdb_print_insn (gdbarch, pc, &buf, NULL);
259  }
260  CATCH (except, RETURN_MASK_ALL)
261  {
263  }
264  END_CATCH
265 
266  result = scm_cons (dascm_make_insn (pc, buf.c_str (), insn_len),
267  result);
268 
269  pc += insn_len;
270  i++;
271  }
272 
273  return scm_reverse_x (result, SCM_EOL);
274 }
275 
276 /* Initialize the Scheme architecture support. */
277 
279 {
280  { "arch-disassemble", 2, 0, 1, as_a_scm_t_subr (gdbscm_arch_disassemble),
281  "\
282 Return list of disassembled instructions in memory.\n\
283 \n\
284  Arguments: <gdb:arch> start-address\n\
285  [#:port port] [#:offset address]\n\
286  [#:size <integer>] [#:count <integer>]\n\
287  port: If non-#f, it is an input port to read bytes from.\n\
288  offset: Specifies the address offset of the first byte in the port.\n\
289  This is useful if the input is from something other than memory\n\
290  (e.g., a bytevector) and you want the result to be as if the bytes\n\
291  came from that address. The value to pass for start-address is\n\
292  then also the desired disassembly address, not the offset in, e.g.,\n\
293  the bytevector.\n\
294  size: Limit the number of bytes read to this amount.\n\
295  count: Limit the number of instructions to this amount.\n\
296 \n\
297  Returns:\n\
298  Each instruction in the result is an alist:\n\
299  (('address . address) ('asm . disassembly) ('length . length))." },
300 
302 };
303 
304 void
306 {
308 
309  port_keyword = scm_from_latin1_keyword ("port");
310  offset_keyword = scm_from_latin1_keyword ("offset");
311  size_keyword = scm_from_latin1_keyword ("size");
312  count_keyword = scm_from_latin1_keyword ("count");
313 
314  address_symbol = scm_from_latin1_symbol ("address");
315  asm_symbol = scm_from_latin1_symbol ("asm");
316  length_symbol = scm_from_latin1_symbol ("length");
317 }
arch_smob * arscm_get_arch_smob_arg_unsafe(SCM arch_scm, int arg_pos, const char *func_name)
Definition: scm-arch.c:151
static scm_t_subr as_a_scm_t_subr(SCM(*func)(void))
void gdbscm_define_functions(const scheme_function *, int is_public)
Definition: scm-utils.c:44
bfd_vma CORE_ADDR
Definition: common-types.h:41
SCM gdbscm_scm_from_ulongest(ULONGEST l)
Definition: scm-utils.c:552
static int branch_delay_insns
Definition: printcmd.c:72
static const scheme_function disasm_functions[]
Definition: scm-disasm.c:278
static SCM length_symbol
Definition: scm-disasm.c:38
int print_insn(CORE_ADDR memaddr, int *branch_delay_insns=NULL)
Definition: disasm.c:759
static int gdbscm_print_insn_from_port(struct gdbarch *gdbarch, SCM port, ULONGEST offset, CORE_ADDR memaddr, string_file *stream, int *branch_delay_insns)
Definition: scm-disasm.c:147
#define FUNC_NAME
struct gdbarch * arscm_get_gdbarch(arch_smob *a_smob)
Definition: scm-arch.c:88
#define _(String)
Definition: gdb_locale.h:35
#define END_CATCH
static SCM gdbscm_arch_disassemble(SCM self, SCM start_scm, SCM rest)
Definition: scm-disasm.c:174
#define gdbscm_is_true(scm)
#define TRY
static SCM count_keyword
Definition: scm-disasm.c:34
static const char * gdbscm_disasm_read_memory_worker(void *datap)
Definition: scm-disasm.c:82
#define CATCH(EXCEPTION, MASK)
unsigned int length
Definition: scm-disasm.c:59
static SCM dascm_make_insn(CORE_ADDR pc, const char *assembly, int insn_len)
Definition: scm-disasm.c:67
const char * gdbscm_with_guile(const char *(*func)(void *), void *data)
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:107
int gdb_print_insn(struct gdbarch *gdbarch, CORE_ADDR memaddr, struct ui_file *stream, int *branch_delay_insns)
Definition: disasm.c:813
static SCM offset_keyword
Definition: scm-disasm.c:32
mach_port_t mach_port_t name mach_port_t mach_port_t name kern_return_t int status
Definition: gnu-nat.c:1822
gdbscm_disassembler(struct gdbarch *gdbarch, struct ui_file *stream, SCM port, ULONGEST offset)
Definition: scm-disasm.c:128
gdbscm_disassembler * dinfo
Definition: scm-disasm.c:60
struct ui_file * stream()
Definition: disasm.h:60
#define END_FUNCTIONS
#define SEEK_SET
Definition: defs.h:93
static SCM size_keyword
Definition: scm-disasm.c:33
const char * c_str() const
Definition: ui-file.h:137
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:305
static SCM address_symbol
Definition: scm-disasm.c:36
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
#define GDBSCM_HANDLE_GDB_EXCEPTION(exception)
size_t size
Definition: go32-nat.c:242