1 /* Scheme interface to architecture.
3 Copyright (C) 2014-2024 Free Software Foundation, Inc.
5 This file is part of GDB.
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.
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.
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/>. */
20 /* See README file in this directory for implementation notes, coding
21 conventions, et.al. */
23 #include "arch-utils.h"
28 #include "guile-internal.h"
30 static SCM port_keyword
;
31 static SCM offset_keyword
;
32 static SCM size_keyword
;
33 static SCM count_keyword
;
35 static SCM address_symbol
;
36 static SCM asm_symbol
;
37 static SCM length_symbol
;
39 class gdbscm_disassembler
: public gdb_disassembler
42 gdbscm_disassembler (struct gdbarch
*gdbarch
,
43 struct ui_file
*stream
,
44 SCM port
, ULONGEST offset
);
47 /* The offset of the address of the first instruction in PORT. */
51 /* Struct used to pass data from gdbscm_disasm_read_memory to
52 gdbscm_disasm_read_memory_worker. */
54 struct gdbscm_disasm_read_data
59 gdbscm_disassembler
*dinfo
;
62 /* Subroutine of gdbscm_arch_disassemble to simplify it.
63 Return the result for one instruction. */
66 dascm_make_insn (CORE_ADDR pc
, const char *assembly
, int insn_len
)
68 return scm_list_3 (scm_cons (address_symbol
,
69 gdbscm_scm_from_ulongest (pc
)),
71 gdbscm_scm_from_c_string (assembly
)),
72 scm_cons (length_symbol
,
73 scm_from_int (insn_len
)));
76 /* Helper function for gdbscm_disasm_read_memory to safely read from a
77 Scheme port. Called via gdbscm_call_guile.
78 The result is a statically allocated error message or NULL if success. */
81 gdbscm_disasm_read_memory_worker (void *datap
)
83 struct gdbscm_disasm_read_data
*data
84 = (struct gdbscm_disasm_read_data
*) datap
;
85 gdbscm_disassembler
*dinfo
= data
->dinfo
;
86 SCM seekto
, newpos
, port
= dinfo
->port
;
89 seekto
= gdbscm_scm_from_ulongest (data
->memaddr
- dinfo
->offset
);
90 newpos
= scm_seek (port
, seekto
, scm_from_int (SEEK_SET
));
91 if (!scm_is_eq (seekto
, newpos
))
94 bytes_read
= scm_c_read (port
, data
->myaddr
, data
->length
);
96 if (bytes_read
!= data
->length
)
99 /* If we get here the read succeeded. */
103 /* disassemble_info.read_memory_func for gdbscm_print_insn_from_port. */
106 gdbscm_disasm_read_memory (bfd_vma memaddr
, bfd_byte
*myaddr
,
108 struct disassemble_info
*dinfo
) noexcept
110 gdbscm_disassembler
*self
111 = static_cast<gdbscm_disassembler
*> (dinfo
->application_data
);
112 struct gdbscm_disasm_read_data data
;
115 data
.memaddr
= memaddr
;
116 data
.myaddr
= myaddr
;
117 data
.length
= length
;
120 status
= gdbscm_with_guile (gdbscm_disasm_read_memory_worker
, &data
);
122 /* TODO: IWBN to distinguish problems reading target memory versus problems
123 with the port (e.g., EOF). */
124 return status
!= NULL
? -1 : 0;
127 gdbscm_disassembler::gdbscm_disassembler (struct gdbarch
*gdbarch
,
128 struct ui_file
*stream
,
129 SCM port_
, ULONGEST offset_
)
130 : gdb_disassembler (gdbarch
, stream
, gdbscm_disasm_read_memory
),
131 port (port_
), offset (offset_
)
135 /* Subroutine of gdbscm_arch_disassemble to simplify it.
136 Call gdbarch_print_insn using a port for input.
137 PORT must be seekable.
138 OFFSET is the offset in PORT from which addresses begin.
139 For example, when printing from a bytevector, addresses passed to the
140 bv seek routines must be in the range [0,size). However, the bytevector
141 may represent an instruction at address 0x1234. To handle this case pass
143 This is based on gdb_print_insn, see it for details. */
146 gdbscm_print_insn_from_port (struct gdbarch
*gdbarch
,
147 SCM port
, ULONGEST offset
, CORE_ADDR memaddr
,
148 string_file
*stream
, int *branch_delay_insns
)
150 gdbscm_disassembler
di (gdbarch
, stream
, port
, offset
);
152 return di
.print_insn (memaddr
, branch_delay_insns
);
155 /* (arch-disassemble <gdb:arch> address
156 [#:port port] [#:offset address] [#:size integer] [#:count integer])
159 Returns a list of disassembled instructions.
160 If PORT is provided, read bytes from it. Otherwise read target memory.
161 If PORT is #f, read target memory.
162 PORT must be seekable. IWBN to remove this restriction, and a future
163 release may. For now the restriction is in place because it's not clear
164 all disassemblers are strictly sequential.
165 If SIZE is provided, limit the number of bytes read to this amount.
166 If COUNT is provided, limit the number of instructions to this amount.
168 Each instruction in the result is an alist:
169 (('address . address) ('asm . disassembly) ('length . length)).
170 We could use a hash table (dictionary) but there aren't that many fields. */
173 gdbscm_arch_disassemble (SCM self
, SCM start_scm
, SCM rest
)
176 = arscm_get_arch_smob_arg_unsafe (self
, SCM_ARG1
, FUNC_NAME
);
177 struct gdbarch
*gdbarch
= arscm_get_gdbarch (a_smob
);
178 const SCM keywords
[] = {
179 port_keyword
, offset_keyword
, size_keyword
, count_keyword
, SCM_BOOL_F
181 int port_arg_pos
= -1, offset_arg_pos
= -1;
182 int size_arg_pos
= -1, count_arg_pos
= -1;
183 SCM port
= SCM_BOOL_F
;
185 unsigned int count
= 1;
188 CORE_ADDR start
, end
;
194 gdbscm_parse_function_args (FUNC_NAME
, SCM_ARG2
, keywords
, "U#OUuu",
195 start_scm
, &start_arg
, rest
,
196 &port_arg_pos
, &port
,
197 &offset_arg_pos
, &offset
,
198 &size_arg_pos
, &size
,
199 &count_arg_pos
, &count
);
200 /* START is first stored in a ULONGEST because we don't have a format char
201 for CORE_ADDR, and it's not really worth it to have one yet. */
204 if (port_arg_pos
> 0)
206 SCM_ASSERT_TYPE (gdbscm_is_false (port
)
207 || gdbscm_is_true (scm_input_port_p (port
)),
208 port
, port_arg_pos
, FUNC_NAME
, _("input port"));
210 using_port
= gdbscm_is_true (port
);
212 if (offset_arg_pos
> 0
214 || gdbscm_is_false (port
)))
216 gdbscm_out_of_range_error (FUNC_NAME
, offset_arg_pos
,
217 gdbscm_scm_from_ulongest (offset
),
218 _("offset provided but port is missing"));
221 if (size_arg_pos
> 0)
225 /* For now be strict about start+size overflowing. If it becomes
226 a nuisance we can relax things later. */
227 if (start
+ size
< start
)
229 gdbscm_out_of_range_error (FUNC_NAME
, 0,
230 scm_list_2 (gdbscm_scm_from_ulongest (start
),
231 gdbscm_scm_from_ulongest (size
)),
232 _("start+size overflows"));
234 end
= start
+ size
- 1;
237 end
= ~(CORE_ADDR
) 0;
244 for (pc
= start
, i
= 0; pc
<= end
&& i
< count
; )
249 gdbscm_gdb_exception exc
{};
254 insn_len
= gdbscm_print_insn_from_port (gdbarch
, port
, offset
,
258 insn_len
= gdb_print_insn (gdbarch
, pc
, &buf
, NULL
);
260 catch (const gdb_exception
&except
)
262 exc
= unpack (except
);
265 GDBSCM_HANDLE_GDB_EXCEPTION (exc
);
266 result
= scm_cons (dascm_make_insn (pc
, buf
.c_str (), insn_len
),
273 return scm_reverse_x (result
, SCM_EOL
);
276 /* Initialize the Scheme architecture support. */
278 static const scheme_function disasm_functions
[] =
280 { "arch-disassemble", 2, 0, 1, as_a_scm_t_subr (gdbscm_arch_disassemble
),
282 Return list of disassembled instructions in memory.\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\
294 size: Limit the number of bytes read to this amount.\n\
295 count: Limit the number of instructions to this amount.\n\
298 Each instruction in the result is an alist:\n\
299 (('address . address) ('asm . disassembly) ('length . length))." },
305 gdbscm_initialize_disasm (void)
307 gdbscm_define_functions (disasm_functions
, 1);
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");
314 address_symbol
= scm_from_latin1_symbol ("address");
315 asm_symbol
= scm_from_latin1_symbol ("asm");
316 length_symbol
= scm_from_latin1_symbol ("length");