New function null_stream
[deliverable/binutils-gdb.git] / gdb / guile / scm-disasm.c
CommitLineData
ed3ef339
DE
1/* Scheme interface to architecture.
2
61baf725 3 Copyright (C) 2014-2017 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
c5192092 79static const char *
ed3ef339
DE
80gdbscm_disasm_read_memory_worker (void *datap)
81{
9a3c8263
SM
82 struct gdbscm_disasm_read_data *data
83 = (struct gdbscm_disasm_read_data *) datap;
ed3ef339 84 struct disassemble_info *dinfo = data->dinfo;
9a3c8263
SM
85 struct gdbscm_disasm_data *disasm_data
86 = (struct gdbscm_disasm_data *) dinfo->application_data;
ed3ef339
DE
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
106static int
107gdbscm_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;
c5192092 112 const char *status;
ed3ef339
DE
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
9a4073e2
PA
122 with the port (e.g., EOF). */
123 return status != NULL ? -1 : 0;
ed3ef339
DE
124}
125
126/* disassemble_info.memory_error_func for gdbscm_print_insn_from_port.
127 Technically speaking, we don't need our own memory_error_func,
128 but to not provide one would leave a subtle dependency in the code.
129 This function exists to keep a clear boundary. */
130
131static void
132gdbscm_disasm_memory_error (int status, bfd_vma memaddr,
133 struct disassemble_info *info)
134{
9a4073e2 135 memory_error (TARGET_XFER_E_IO, memaddr);
ed3ef339
DE
136}
137
138/* disassemble_info.print_address_func for gdbscm_print_insn_from_port.
139 Since we need to use our own application_data value, we need to supply
140 this routine as well. */
141
142static void
143gdbscm_disasm_print_address (bfd_vma addr, struct disassemble_info *info)
144{
9a3c8263
SM
145 struct gdbscm_disasm_data *data
146 = (struct gdbscm_disasm_data *) info->application_data;
ed3ef339
DE
147 struct gdbarch *gdbarch = data->gdbarch;
148
9a3c8263 149 print_address (gdbarch, addr, (struct ui_file *) info->stream);
ed3ef339
DE
150}
151
152/* Subroutine of gdbscm_arch_disassemble to simplify it.
153 Call gdbarch_print_insn using a port for input.
154 PORT must be seekable.
155 OFFSET is the offset in PORT from which addresses begin.
156 For example, when printing from a bytevector, addresses passed to the
157 bv seek routines must be in the range [0,size). However, the bytevector
158 may represent an instruction at address 0x1234. To handle this case pass
159 0x1234 for OFFSET.
160 This is based on gdb_print_insn, see it for details. */
161
162static int
163gdbscm_print_insn_from_port (struct gdbarch *gdbarch,
164 SCM port, ULONGEST offset, CORE_ADDR memaddr,
165 struct ui_file *stream, int *branch_delay_insns)
166{
167 struct disassemble_info di;
168 int length;
169 struct gdbscm_disasm_data data;
170
171 di = gdb_disassemble_info (gdbarch, stream);
172 data.gdbarch = gdbarch;
173 data.port = port;
174 data.offset = offset;
175 di.application_data = &data;
176 di.read_memory_func = gdbscm_disasm_read_memory;
177 di.memory_error_func = gdbscm_disasm_memory_error;
178 di.print_address_func = gdbscm_disasm_print_address;
179
180 length = gdbarch_print_insn (gdbarch, memaddr, &di);
181
182 if (branch_delay_insns)
183 {
184 if (di.insn_info_valid)
185 *branch_delay_insns = di.branch_delay_insns;
186 else
187 *branch_delay_insns = 0;
188 }
189
190 return length;
191}
192
193/* (arch-disassemble <gdb:arch> address
194 [#:port port] [#:offset address] [#:size integer] [#:count integer])
195 -> list
196
197 Returns a list of disassembled instructions.
198 If PORT is provided, read bytes from it. Otherwise read target memory.
199 If PORT is #f, read target memory.
200 PORT must be seekable. IWBN to remove this restriction, and a future
201 release may. For now the restriction is in place because it's not clear
202 all disassemblers are strictly sequential.
203 If SIZE is provided, limit the number of bytes read to this amount.
204 If COUNT is provided, limit the number of instructions to this amount.
205
206 Each instruction in the result is an alist:
207 (('address . address) ('asm . disassembly) ('length . length)).
208 We could use a hash table (dictionary) but there aren't that many fields. */
209
210static SCM
211gdbscm_arch_disassemble (SCM self, SCM start_scm, SCM rest)
212{
213 arch_smob *a_smob
214 = arscm_get_arch_smob_arg_unsafe (self, SCM_ARG1, FUNC_NAME);
215 struct gdbarch *gdbarch = arscm_get_gdbarch (a_smob);
216 const SCM keywords[] = {
217 port_keyword, offset_keyword, size_keyword, count_keyword, SCM_BOOL_F
218 };
219 int port_arg_pos = -1, offset_arg_pos = -1;
220 int size_arg_pos = -1, count_arg_pos = -1;
221 SCM port = SCM_BOOL_F;
222 ULONGEST offset = 0;
223 unsigned int count = 1;
224 unsigned int size;
225 ULONGEST start_arg;
226 CORE_ADDR start, end;
227 CORE_ADDR pc;
228 unsigned int i;
229 int using_port;
230 SCM result;
231
232 gdbscm_parse_function_args (FUNC_NAME, SCM_ARG2, keywords, "U#OUuu",
233 start_scm, &start_arg, rest,
234 &port_arg_pos, &port,
235 &offset_arg_pos, &offset,
236 &size_arg_pos, &size,
237 &count_arg_pos, &count);
238 /* START is first stored in a ULONGEST because we don't have a format char
239 for CORE_ADDR, and it's not really worth it to have one yet. */
240 start = start_arg;
241
242 if (port_arg_pos > 0)
243 {
244 SCM_ASSERT_TYPE (gdbscm_is_false (port)
245 || gdbscm_is_true (scm_input_port_p (port)),
246 port, port_arg_pos, FUNC_NAME, _("input port"));
247 }
248 using_port = gdbscm_is_true (port);
249
250 if (offset_arg_pos > 0
251 && (port_arg_pos < 0
252 || gdbscm_is_false (port)))
253 {
254 gdbscm_out_of_range_error (FUNC_NAME, offset_arg_pos,
255 gdbscm_scm_from_ulongest (offset),
256 _("offset provided but port is missing"));
257 }
258
259 if (size_arg_pos > 0)
260 {
261 if (size == 0)
262 return SCM_EOL;
263 /* For now be strict about start+size overflowing. If it becomes
264 a nuisance we can relax things later. */
265 if (start + size < start)
266 {
267 gdbscm_out_of_range_error (FUNC_NAME, 0,
268 scm_list_2 (gdbscm_scm_from_ulongest (start),
269 gdbscm_scm_from_ulongest (size)),
270 _("start+size overflows"));
271 }
272 end = start + size - 1;
273 }
274 else
275 end = ~(CORE_ADDR) 0;
276
277 if (count == 0)
278 return SCM_EOL;
279
280 result = SCM_EOL;
281
282 for (pc = start, i = 0; pc <= end && i < count; )
283 {
284 int insn_len = 0;
ed3ef339
DE
285 struct ui_file *memfile = mem_fileopen ();
286 struct cleanup *cleanups = make_cleanup_ui_file_delete (memfile);
ed3ef339 287
492d29ea 288 TRY
ed3ef339
DE
289 {
290 if (using_port)
291 {
292 insn_len = gdbscm_print_insn_from_port (gdbarch, port, offset,
293 pc, memfile, NULL);
294 }
295 else
296 insn_len = gdb_print_insn (gdbarch, pc, memfile, NULL);
297 }
492d29ea
PA
298 CATCH (except, RETURN_MASK_ALL)
299 {
300 GDBSCM_HANDLE_GDB_EXCEPTION_WITH_CLEANUPS (except, cleanups);
301 }
302 END_CATCH
ed3ef339 303
3ab692db 304 std::string as = ui_file_as_string (memfile);
ed3ef339 305
3ab692db 306 result = scm_cons (dascm_make_insn (pc, as.c_str (), insn_len),
ed3ef339
DE
307 result);
308
309 pc += insn_len;
310 i++;
311 do_cleanups (cleanups);
ed3ef339
DE
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.414431 seconds and 4 git commands to generate.