Add some more casts (1/2)
[deliverable/binutils-gdb.git] / gdb / guile / scm-disasm.c
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
42 struct gdbscm_disasm_data
43 {
44 struct gdbarch *gdbarch;
45 SCM port;
46 /* The offset of the address of the first instruction in PORT. */
47 ULONGEST offset;
48 };
49
50 /* Struct used to pass data from gdbscm_disasm_read_memory to
51 gdbscm_disasm_read_memory_worker. */
52
53 struct gdbscm_disasm_read_data
54 {
55 bfd_vma memaddr;
56 bfd_byte *myaddr;
57 unsigned int length;
58 struct disassemble_info *dinfo;
59 };
60 \f
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,
68 gdbscm_scm_from_ulongest (pc)),
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 *
80 gdbscm_disasm_read_memory_worker (void *datap)
81 {
82 struct gdbscm_disasm_read_data *data
83 = (struct gdbscm_disasm_read_data *) datap;
84 struct disassemble_info *dinfo = data->dinfo;
85 struct gdbscm_disasm_data *disasm_data
86 = (struct gdbscm_disasm_data *) dinfo->application_data;
87 SCM seekto, newpos, port = disasm_data->port;
88 size_t bytes_read;
89
90 seekto = gdbscm_scm_from_ulongest (data->memaddr - disasm_data->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
107 gdbscm_disasm_read_memory (bfd_vma memaddr, bfd_byte *myaddr,
108 unsigned int length,
109 struct disassemble_info *dinfo)
110 {
111 struct gdbscm_disasm_read_data data;
112 void *status;
113
114 data.memaddr = memaddr;
115 data.myaddr = myaddr;
116 data.length = length;
117 data.dinfo = dinfo;
118
119 status = gdbscm_with_guile (gdbscm_disasm_read_memory_worker, &data);
120
121 /* TODO: IWBN to distinguish problems reading target memory versus problems
122 with the port (e.g., EOF).
123 We return TARGET_XFER_E_IO here as that's what memory_error looks for. */
124 return status != NULL ? TARGET_XFER_E_IO : 0;
125 }
126
127 /* disassemble_info.memory_error_func for gdbscm_print_insn_from_port.
128 Technically speaking, we don't need our own memory_error_func,
129 but to not provide one would leave a subtle dependency in the code.
130 This function exists to keep a clear boundary. */
131
132 static void
133 gdbscm_disasm_memory_error (int status, bfd_vma memaddr,
134 struct disassemble_info *info)
135 {
136 memory_error (status, memaddr);
137 }
138
139 /* disassemble_info.print_address_func for gdbscm_print_insn_from_port.
140 Since we need to use our own application_data value, we need to supply
141 this routine as well. */
142
143 static void
144 gdbscm_disasm_print_address (bfd_vma addr, struct disassemble_info *info)
145 {
146 struct gdbscm_disasm_data *data
147 = (struct gdbscm_disasm_data *) info->application_data;
148 struct gdbarch *gdbarch = data->gdbarch;
149
150 print_address (gdbarch, addr, (struct ui_file *) info->stream);
151 }
152
153 /* Subroutine of gdbscm_arch_disassemble to simplify it.
154 Call gdbarch_print_insn using a port for input.
155 PORT must be seekable.
156 OFFSET is the offset in PORT from which addresses begin.
157 For example, when printing from a bytevector, addresses passed to the
158 bv seek routines must be in the range [0,size). However, the bytevector
159 may represent an instruction at address 0x1234. To handle this case pass
160 0x1234 for OFFSET.
161 This is based on gdb_print_insn, see it for details. */
162
163 static int
164 gdbscm_print_insn_from_port (struct gdbarch *gdbarch,
165 SCM port, ULONGEST offset, CORE_ADDR memaddr,
166 struct ui_file *stream, int *branch_delay_insns)
167 {
168 struct disassemble_info di;
169 int length;
170 struct gdbscm_disasm_data data;
171
172 di = gdb_disassemble_info (gdbarch, stream);
173 data.gdbarch = gdbarch;
174 data.port = port;
175 data.offset = offset;
176 di.application_data = &data;
177 di.read_memory_func = gdbscm_disasm_read_memory;
178 di.memory_error_func = gdbscm_disasm_memory_error;
179 di.print_address_func = gdbscm_disasm_print_address;
180
181 length = gdbarch_print_insn (gdbarch, memaddr, &di);
182
183 if (branch_delay_insns)
184 {
185 if (di.insn_info_valid)
186 *branch_delay_insns = di.branch_delay_insns;
187 else
188 *branch_delay_insns = 0;
189 }
190
191 return length;
192 }
193
194 /* (arch-disassemble <gdb:arch> address
195 [#:port port] [#:offset address] [#:size integer] [#:count integer])
196 -> list
197
198 Returns a list of disassembled instructions.
199 If PORT is provided, read bytes from it. Otherwise read target memory.
200 If PORT is #f, read target memory.
201 PORT must be seekable. IWBN to remove this restriction, and a future
202 release may. For now the restriction is in place because it's not clear
203 all disassemblers are strictly sequential.
204 If SIZE is provided, limit the number of bytes read to this amount.
205 If COUNT is provided, limit the number of instructions to this amount.
206
207 Each instruction in the result is an alist:
208 (('address . address) ('asm . disassembly) ('length . length)).
209 We could use a hash table (dictionary) but there aren't that many fields. */
210
211 static SCM
212 gdbscm_arch_disassemble (SCM self, SCM start_scm, SCM rest)
213 {
214 arch_smob *a_smob
215 = arscm_get_arch_smob_arg_unsafe (self, SCM_ARG1, FUNC_NAME);
216 struct gdbarch *gdbarch = arscm_get_gdbarch (a_smob);
217 const SCM keywords[] = {
218 port_keyword, offset_keyword, size_keyword, count_keyword, SCM_BOOL_F
219 };
220 int port_arg_pos = -1, offset_arg_pos = -1;
221 int size_arg_pos = -1, count_arg_pos = -1;
222 SCM port = SCM_BOOL_F;
223 ULONGEST offset = 0;
224 unsigned int count = 1;
225 unsigned int size;
226 ULONGEST start_arg;
227 CORE_ADDR start, end;
228 CORE_ADDR pc;
229 unsigned int i;
230 int using_port;
231 SCM result;
232
233 gdbscm_parse_function_args (FUNC_NAME, SCM_ARG2, keywords, "U#OUuu",
234 start_scm, &start_arg, rest,
235 &port_arg_pos, &port,
236 &offset_arg_pos, &offset,
237 &size_arg_pos, &size,
238 &count_arg_pos, &count);
239 /* START is first stored in a ULONGEST because we don't have a format char
240 for CORE_ADDR, and it's not really worth it to have one yet. */
241 start = start_arg;
242
243 if (port_arg_pos > 0)
244 {
245 SCM_ASSERT_TYPE (gdbscm_is_false (port)
246 || gdbscm_is_true (scm_input_port_p (port)),
247 port, port_arg_pos, FUNC_NAME, _("input port"));
248 }
249 using_port = gdbscm_is_true (port);
250
251 if (offset_arg_pos > 0
252 && (port_arg_pos < 0
253 || gdbscm_is_false (port)))
254 {
255 gdbscm_out_of_range_error (FUNC_NAME, offset_arg_pos,
256 gdbscm_scm_from_ulongest (offset),
257 _("offset provided but port is missing"));
258 }
259
260 if (size_arg_pos > 0)
261 {
262 if (size == 0)
263 return SCM_EOL;
264 /* For now be strict about start+size overflowing. If it becomes
265 a nuisance we can relax things later. */
266 if (start + size < start)
267 {
268 gdbscm_out_of_range_error (FUNC_NAME, 0,
269 scm_list_2 (gdbscm_scm_from_ulongest (start),
270 gdbscm_scm_from_ulongest (size)),
271 _("start+size overflows"));
272 }
273 end = start + size - 1;
274 }
275 else
276 end = ~(CORE_ADDR) 0;
277
278 if (count == 0)
279 return SCM_EOL;
280
281 result = SCM_EOL;
282
283 for (pc = start, i = 0; pc <= end && i < count; )
284 {
285 int insn_len = 0;
286 char *as = NULL;
287 struct ui_file *memfile = mem_fileopen ();
288 struct cleanup *cleanups = make_cleanup_ui_file_delete (memfile);
289
290 TRY
291 {
292 if (using_port)
293 {
294 insn_len = gdbscm_print_insn_from_port (gdbarch, port, offset,
295 pc, memfile, NULL);
296 }
297 else
298 insn_len = gdb_print_insn (gdbarch, pc, memfile, NULL);
299 }
300 CATCH (except, RETURN_MASK_ALL)
301 {
302 GDBSCM_HANDLE_GDB_EXCEPTION_WITH_CLEANUPS (except, cleanups);
303 }
304 END_CATCH
305
306 as = ui_file_xstrdup (memfile, NULL);
307
308 result = scm_cons (dascm_make_insn (pc, as, insn_len),
309 result);
310
311 pc += insn_len;
312 i++;
313 do_cleanups (cleanups);
314 xfree (as);
315 }
316
317 return scm_reverse_x (result, SCM_EOL);
318 }
319 \f
320 /* Initialize the Scheme architecture support. */
321
322 static const scheme_function disasm_functions[] =
323 {
324 { "arch-disassemble", 2, 0, 1, as_a_scm_t_subr (gdbscm_arch_disassemble),
325 "\
326 Return list of disassembled instructions in memory.\n\
327 \n\
328 Arguments: <gdb:arch> start-address\n\
329 [#:port port] [#:offset address]\n\
330 [#:size <integer>] [#:count <integer>]\n\
331 port: If non-#f, it is an input port to read bytes from.\n\
332 offset: Specifies the address offset of the first byte in the port.\n\
333 This is useful if the input is from something other than memory\n\
334 (e.g., a bytevector) and you want the result to be as if the bytes\n\
335 came from that address. The value to pass for start-address is\n\
336 then also the desired disassembly address, not the offset in, e.g.,\n\
337 the bytevector.\n\
338 size: Limit the number of bytes read to this amount.\n\
339 count: Limit the number of instructions to this amount.\n\
340 \n\
341 Returns:\n\
342 Each instruction in the result is an alist:\n\
343 (('address . address) ('asm . disassembly) ('length . length))." },
344
345 END_FUNCTIONS
346 };
347
348 void
349 gdbscm_initialize_disasm (void)
350 {
351 gdbscm_define_functions (disasm_functions, 1);
352
353 port_keyword = scm_from_latin1_keyword ("port");
354 offset_keyword = scm_from_latin1_keyword ("offset");
355 size_keyword = scm_from_latin1_keyword ("size");
356 count_keyword = scm_from_latin1_keyword ("count");
357
358 address_symbol = scm_from_latin1_symbol ("address");
359 asm_symbol = scm_from_latin1_symbol ("asm");
360 length_symbol = scm_from_latin1_symbol ("length");
361 }
This page took 0.036821 seconds and 4 git commands to generate.