GDB (xrefs)

scm-disasm.c
Go to the documentation of this file.
1 /* Scheme interface to architecture.
2
3 Copyright (C) 2014-2018 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 class gdbscm_disassembler : public gdb_disassembler
41 {
42 public:
43 gdbscm_disassembler (struct gdbarch *gdbarch,
44 struct ui_file *stream,
45 SCM port, ULONGEST offset);
46
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
55 struct gdbscm_disasm_read_data
56 {
57 bfd_vma memaddr;
58 bfd_byte *myaddr;
59 unsigned int length;
60 gdbscm_disassembler *dinfo;
61 };
62
63 /* Subroutine of gdbscm_arch_disassemble to simplify it.
64 Return the result for one instruction. */
65
66 static SCM
67 dascm_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
81 static const char *
82 gdbscm_disasm_read_memory_worker (void *datap)
83 {
84 struct gdbscm_disasm_read_data *data
85 = (struct gdbscm_disasm_read_data *) datap;
86 gdbscm_disassembler *dinfo = data->dinfo;
87 SCM seekto, newpos, port = dinfo->port;
88 size_t bytes_read;
89
90 seekto = gdbscm_scm_from_ulongest (data->memaddr - dinfo->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 gdbscm_disassembler *self
112 = static_cast<gdbscm_disassembler *> (dinfo->application_data);
113 struct gdbscm_disasm_read_data data;
114 const char *status;
115
116 data.memaddr = memaddr;
117 data.myaddr = myaddr;
118 data.length = length;
119 data.dinfo = self;
120
121 status = gdbscm_with_guile (gdbscm_disasm_read_memory_worker, &data);
122
123 /* TODO: IWBN to distinguish problems reading target memory versus problems
124 with the port (e.g., EOF). */
125 return status != NULL ? -1 : 0;
126 }
127
128 gdbscm_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_)
133 {
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
146 static int
147 gdbscm_print_insn_from_port (struct gdbarch *gdbarch,
148 SCM port, ULONGEST offset, CORE_ADDR memaddr,
149 string_file *stream, int *branch_delay_insns)
150 {
151 gdbscm_disassembler di (gdbarch, stream, port, offset);
152
153 return di.print_insn (memaddr, branch_delay_insns);
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
173 static SCM
174 gdbscm_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;
248 string_file buf;
249
250 TRY
251 {
252 if (using_port)
253 {
254 insn_len = gdbscm_print_insn_from_port (gdbarch, port, offset,
255 pc, &buf, NULL);
256 }
257 else
258 insn_len = gdb_print_insn (gdbarch, pc, &buf, NULL);
259 }
260 CATCH (except, RETURN_MASK_ALL)
261 {
262 GDBSCM_HANDLE_GDB_EXCEPTION (except);
263 }
264 END_CATCH
265
266 result = scm_cons (dascm_make_insn (pc, buf.c_str (), insn_len),
267 result);
268
269 pc += insn_len;
270 i++;
271 }
272
273 return scm_reverse_x (result, SCM_EOL);
274 }
275
276 /* Initialize the Scheme architecture support. */
277
278 static const scheme_function disasm_functions[] =
279 {
280 { "arch-disassemble", 2, 0, 1, as_a_scm_t_subr (gdbscm_arch_disassemble),
281 "\
282 Return list of disassembled instructions in memory.\n\
283 \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\
293 the bytevector.\n\
294 size: Limit the number of bytes read to this amount.\n\
295 count: Limit the number of instructions to this amount.\n\
296 \n\
297 Returns:\n\
298 Each instruction in the result is an alist:\n\
299 (('address . address) ('asm . disassembly) ('length . length))." },
300
301 END_FUNCTIONS
302 };
303
304 void
305 gdbscm_initialize_disasm (void)
306 {
307 gdbscm_define_functions (disasm_functions, 1);
308
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");
313
314 address_symbol = scm_from_latin1_symbol ("address");
315 asm_symbol = scm_from_latin1_symbol ("asm");
316 length_symbol = scm_from_latin1_symbol ("length");
317 }
gdbarch
Definition: gdbarch.c:127
arscm_get_arch_smob_arg_unsafe
arch_smob * arscm_get_arch_smob_arg_unsafe(SCM arch_scm, int arg_pos, const char *func_name)
Definition: scm-arch.c:151
as_a_scm_t_subr
static scm_t_subr as_a_scm_t_subr(SCM(*func)(void))
Definition: guile-internal.h:66
gdbscm_define_functions
void gdbscm_define_functions(const scheme_function *, int is_public)
Definition: scm-utils.c:44
CORE_ADDR
bfd_vma CORE_ADDR
Definition: common-types.h:41
RETURN_MASK_ALL
Definition: common-exceptions.h:44
gdbscm_scm_from_ulongest
SCM gdbscm_scm_from_ulongest(ULONGEST l)
Definition: scm-utils.c:552
_arch_smob
Definition: scm-arch.c:32
branch_delay_insns
static int branch_delay_insns
Definition: printcmd.c:72
disasm_functions
static const scheme_function disasm_functions[]
Definition: scm-disasm.c:278
gdbscm_disasm_read_data::myaddr
bfd_byte * myaddr
Definition: scm-disasm.c:58
length_symbol
static SCM length_symbol
Definition: scm-disasm.c:38
gdb_disassembler::print_insn
int print_insn(CORE_ADDR memaddr, int *branch_delay_insns=NULL)
Definition: disasm.c:759
gdbscm_print_insn_from_port
static int gdbscm_print_insn_from_port(struct gdbarch *gdbarch, SCM port, ULONGEST offset, CORE_ADDR memaddr, string_file *stream, int *branch_delay_insns)
Definition: scm-disasm.c:147
FUNC_NAME
#define FUNC_NAME
Definition: guile-internal.h:153
guile-internal.h
disasm.h
arscm_get_gdbarch
struct gdbarch * arscm_get_gdbarch(arch_smob *a_smob)
Definition: scm-arch.c:88
_
#define _(String)
Definition: gdb_locale.h:35
ui_file
Definition: ui-file.h:26
defs.h
END_CATCH
#define END_CATCH
Definition: common-exceptions.h:259
gdbscm_arch_disassemble
static SCM gdbscm_arch_disassemble(SCM self, SCM start_scm, SCM rest)
Definition: scm-disasm.c:174
gdbscm_is_true
#define gdbscm_is_true(scm)
Definition: guile-internal.h:134
arch-utils.h
TRY
#define TRY
Definition: common-exceptions.h:246
count_keyword
static SCM count_keyword
Definition: scm-disasm.c:34
gdbscm_disasm_read_data::memaddr
bfd_vma memaddr
Definition: scm-disasm.c:57
gdbscm_disasm_read_memory_worker
static const char * gdbscm_disasm_read_memory_worker(void *datap)
Definition: scm-disasm.c:82
CATCH
#define CATCH(EXCEPTION, MASK)
Definition: common-exceptions.h:254
gdbscm_disasm_read_data::length
unsigned int length
Definition: scm-disasm.c:59
dascm_make_insn
static SCM dascm_make_insn(CORE_ADDR pc, const char *assembly, int insn_len)
Definition: scm-disasm.c:67
gdbscm_disassembler::offset
ULONGEST offset
Definition: scm-disasm.c:49
gdbscm_with_guile
const char * gdbscm_with_guile(const char *(*func)(void *), void *data)
Definition: scm-safe-call.c:171
gdbscm_scm_from_c_string
SCM gdbscm_scm_from_c_string(const char *string)
Definition: scm-string.c:44
asm_symbol
static SCM asm_symbol
Definition: scm-disasm.c:37
gdbscm_is_false
#define gdbscm_is_false(scm)
Definition: guile-internal.h:133
gdbscm_disasm_read_data
Definition: scm-disasm.c:55
gdbscm_disasm_read_memory
static int gdbscm_disasm_read_memory(bfd_vma memaddr, bfd_byte *myaddr, unsigned int length, struct disassemble_info *dinfo)
Definition: scm-disasm.c:107
gdb_print_insn
int gdb_print_insn(struct gdbarch *gdbarch, CORE_ADDR memaddr, struct ui_file *stream, int *branch_delay_insns)
Definition: disasm.c:813
gdbarch.h
scheme_function
Definition: guile-internal.h:91
offset_keyword
static SCM offset_keyword
Definition: scm-disasm.c:32
status
mach_port_t mach_port_t name mach_port_t mach_port_t name kern_return_t int status
Definition: gnu-nat.c:1822
gdbscm_disassembler::gdbscm_disassembler
gdbscm_disassembler(struct gdbarch *gdbarch, struct ui_file *stream, SCM port, ULONGEST offset)
Definition: scm-disasm.c:128
gdbscm_disassembler::port
SCM port
Definition: scm-disasm.c:47
gdbscm_disassembler
Definition: scm-disasm.c:40
gdbscm_disasm_read_data::dinfo
gdbscm_disassembler * dinfo
Definition: scm-disasm.c:60
gdb_disassembler
Definition: disasm.h:41
gdb_disassembler::stream
struct ui_file * stream()
Definition: disasm.h:60
END_FUNCTIONS
#define END_FUNCTIONS
Definition: guile-internal.h:103
SEEK_SET
#define SEEK_SET
Definition: defs.h:93
gdbcore.h
size_keyword
static SCM size_keyword
Definition: scm-disasm.c:33
string_file::c_str
const char * c_str() const
Definition: ui-file.h:137
port_keyword
static SCM port_keyword
Definition: scm-disasm.c:31
gdbscm_out_of_range_error
void gdbscm_out_of_range_error(const char *subr, int arg_pos, SCM bad_value, const char *error) ATTRIBUTE_NORETURN
Definition: scm-exception.c:349
offset
int offset
Definition: agent.c:65
gdbscm_initialize_disasm
void gdbscm_initialize_disasm(void)
Definition: scm-disasm.c:305
address_symbol
static SCM address_symbol
Definition: scm-disasm.c:36
gdbscm_parse_function_args
void gdbscm_parse_function_args(const char *function_name, int beginning_arg_pos, const SCM *keywords, const char *format,...)
Definition: scm-utils.c:377
ULONGEST
unsigned long long ULONGEST
Definition: common-types.h:53
GDBSCM_HANDLE_GDB_EXCEPTION
#define GDBSCM_HANDLE_GDB_EXCEPTION(exception)
Definition: guile-internal.h:643
size
size_t size
Definition: go32-nat.c:242
string_file
Definition: ui-file.h:106