hurd: add gnu_target pointer to fix thread API calls
[deliverable/binutils-gdb.git] / gdb / guile / scm-disasm.c
CommitLineData
ed3ef339
DE
1/* Scheme interface to architecture.
2
b811d2c2 3 Copyright (C) 2014-2020 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
e47ad6c0 40class gdbscm_disassembler : public gdb_disassembler
ed3ef339 41{
e47ad6c0
YQ
42public:
43 gdbscm_disassembler (struct gdbarch *gdbarch,
44 struct ui_file *stream,
45 SCM port, ULONGEST offset);
46
ed3ef339
DE
47 SCM port;
48 /* The offset of the address of the first instruction in PORT. */
49 ULONGEST offset;
50};
51
52/* Struct used to pass data from gdbscm_disasm_read_memory to
53 gdbscm_disasm_read_memory_worker. */
54
55struct gdbscm_disasm_read_data
56{
57 bfd_vma memaddr;
58 bfd_byte *myaddr;
59 unsigned int length;
e47ad6c0 60 gdbscm_disassembler *dinfo;
ed3ef339
DE
61};
62\f
63/* Subroutine of gdbscm_arch_disassemble to simplify it.
64 Return the result for one instruction. */
65
66static SCM
67dascm_make_insn (CORE_ADDR pc, const char *assembly, int insn_len)
68{
69 return scm_list_3 (scm_cons (address_symbol,
70 gdbscm_scm_from_ulongest (pc)),
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
c5192092 81static const char *
ed3ef339
DE
82gdbscm_disasm_read_memory_worker (void *datap)
83{
9a3c8263
SM
84 struct gdbscm_disasm_read_data *data
85 = (struct gdbscm_disasm_read_data *) datap;
e47ad6c0
YQ
86 gdbscm_disassembler *dinfo = data->dinfo;
87 SCM seekto, newpos, port = dinfo->port;
ed3ef339
DE
88 size_t bytes_read;
89
e47ad6c0 90 seekto = gdbscm_scm_from_ulongest (data->memaddr - dinfo->offset);
ed3ef339
DE
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{
e47ad6c0
YQ
111 gdbscm_disassembler *self
112 = static_cast<gdbscm_disassembler *> (dinfo->application_data);
ed3ef339 113 struct gdbscm_disasm_read_data data;
c5192092 114 const char *status;
ed3ef339
DE
115
116 data.memaddr = memaddr;
117 data.myaddr = myaddr;
118 data.length = length;
e47ad6c0 119 data.dinfo = self;
ed3ef339
DE
120
121 status = gdbscm_with_guile (gdbscm_disasm_read_memory_worker, &data);
122
123 /* TODO: IWBN to distinguish problems reading target memory versus problems
9a4073e2
PA
124 with the port (e.g., EOF). */
125 return status != NULL ? -1 : 0;
ed3ef339
DE
126}
127
e47ad6c0
YQ
128gdbscm_disassembler::gdbscm_disassembler (struct gdbarch *gdbarch,
129 struct ui_file *stream,
130 SCM port_, ULONGEST offset_)
131 : gdb_disassembler (gdbarch, stream, gdbscm_disasm_read_memory),
132 port (port_), offset (offset_)
ed3ef339 133{
ed3ef339
DE
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
146static int
147gdbscm_print_insn_from_port (struct gdbarch *gdbarch,
148 SCM port, ULONGEST offset, CORE_ADDR memaddr,
d7e74731 149 string_file *stream, int *branch_delay_insns)
ed3ef339 150{
e47ad6c0
YQ
151 gdbscm_disassembler di (gdbarch, stream, port, offset);
152
153 return di.print_insn (memaddr, branch_delay_insns);
ed3ef339
DE
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
173static SCM
174gdbscm_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[] = {
180 port_keyword, offset_keyword, size_keyword, count_keyword, SCM_BOOL_F
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,
218 gdbscm_scm_from_ulongest (offset),
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 {
230 gdbscm_out_of_range_error (FUNC_NAME, 0,
231 scm_list_2 (gdbscm_scm_from_ulongest (start),
232 gdbscm_scm_from_ulongest (size)),
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;
d7e74731 248 string_file buf;
ed3ef339 249
680d7fd5 250 gdbscm_gdb_exception exc {};
a70b8144 251 try
ed3ef339
DE
252 {
253 if (using_port)
254 {
255 insn_len = gdbscm_print_insn_from_port (gdbarch, port, offset,
d7e74731 256 pc, &buf, NULL);
ed3ef339
DE
257 }
258 else
d7e74731 259 insn_len = gdb_print_insn (gdbarch, pc, &buf, NULL);
ed3ef339 260 }
230d2906 261 catch (const gdb_exception &except)
492d29ea 262 {
680d7fd5 263 exc = unpack (except);
492d29ea 264 }
ed3ef339 265
680d7fd5 266 GDBSCM_HANDLE_GDB_EXCEPTION (exc);
d7e74731 267 result = scm_cons (dascm_make_insn (pc, buf.c_str (), insn_len),
ed3ef339
DE
268 result);
269
270 pc += insn_len;
271 i++;
ed3ef339
DE
272 }
273
274 return scm_reverse_x (result, SCM_EOL);
275}
276\f
277/* Initialize the Scheme architecture support. */
278
279static const scheme_function disasm_functions[] =
280{
72e02483 281 { "arch-disassemble", 2, 0, 1, as_a_scm_t_subr (gdbscm_arch_disassemble),
ed3ef339
DE
282 "\
283Return list of disassembled instructions in memory.\n\
284\n\
285 Arguments: <gdb:arch> start-address\n\
286 [#:port port] [#:offset address]\n\
287 [#:size <integer>] [#:count <integer>]\n\
288 port: If non-#f, it is an input port to read bytes from.\n\
289 offset: Specifies the address offset of the first byte in the port.\n\
290 This is useful if the input is from something other than memory\n\
291 (e.g., a bytevector) and you want the result to be as if the bytes\n\
292 came from that address. The value to pass for start-address is\n\
293 then also the desired disassembly address, not the offset in, e.g.,\n\
294 the bytevector.\n\
295 size: Limit the number of bytes read to this amount.\n\
296 count: Limit the number of instructions to this amount.\n\
297\n\
298 Returns:\n\
299 Each instruction in the result is an alist:\n\
300 (('address . address) ('asm . disassembly) ('length . length))." },
301
302 END_FUNCTIONS
303};
304
305void
306gdbscm_initialize_disasm (void)
307{
308 gdbscm_define_functions (disasm_functions, 1);
309
310 port_keyword = scm_from_latin1_keyword ("port");
311 offset_keyword = scm_from_latin1_keyword ("offset");
312 size_keyword = scm_from_latin1_keyword ("size");
313 count_keyword = scm_from_latin1_keyword ("count");
314
315 address_symbol = scm_from_latin1_symbol ("address");
316 asm_symbol = scm_from_latin1_symbol ("asm");
317 length_symbol = scm_from_latin1_symbol ("length");
318}
This page took 0.739032 seconds and 4 git commands to generate.