Add casts to memory allocation related calls
[deliverable/binutils-gdb.git] / gdb / guile / scm-disasm.c
CommitLineData
ed3ef339
DE
1/* Scheme interface to architecture.
2
32d0add0 3 Copyright (C) 2014-2015 Free Software Foundation, Inc.
ed3ef339
DE
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
31static SCM port_keyword;
32static SCM offset_keyword;
33static SCM size_keyword;
34static SCM count_keyword;
35
36static SCM address_symbol;
37static SCM asm_symbol;
38static SCM length_symbol;
39
40/* Struct used to pass "application data" in disassemble_info. */
41
42struct 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
53struct 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
64static SCM
65dascm_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
79static void *
80gdbscm_disasm_read_memory_worker (void *datap)
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
104static int
105gdbscm_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
117 status = gdbscm_with_guile (gdbscm_disasm_read_memory_worker, &data);
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
130static void
131gdbscm_disasm_memory_error (int status, bfd_vma memaddr,
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
141static void
142gdbscm_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
160static int
161gdbscm_print_insn_from_port (struct gdbarch *gdbarch,
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
208static SCM
209gdbscm_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[] = {
215 port_keyword, offset_keyword, size_keyword, count_keyword, SCM_BOOL_F
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 {
265 gdbscm_out_of_range_error (FUNC_NAME, 0,
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);
ed3ef339 286
492d29ea 287 TRY
ed3ef339
DE
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 }
492d29ea
PA
297 CATCH (except, RETURN_MASK_ALL)
298 {
299 GDBSCM_HANDLE_GDB_EXCEPTION_WITH_CLEANUPS (except, cleanups);
300 }
301 END_CATCH
ed3ef339
DE
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\f
317/* Initialize the Scheme architecture support. */
318
319static const scheme_function disasm_functions[] =
320{
72e02483 321 { "arch-disassemble", 2, 0, 1, as_a_scm_t_subr (gdbscm_arch_disassemble),
ed3ef339
DE
322 "\
323Return 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
342 END_FUNCTIONS
343};
344
345void
346gdbscm_initialize_disasm (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}
This page took 0.171857 seconds and 4 git commands to generate.