* Copyright (c) 1991 The Regents of the University of California.
* This code is derived from software contributed to Berkeley by
* Van Jacobson and Steven McCanne of Lawrence Berkeley Laboratory.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* $Header: remote.c,v 1.24 91/03/22 15:35:15 mccanne Exp $;
static char sccsid
[] = "@(#)remote.c 6.5 (Berkeley) 5/8/91";
extern int kernel_debugging
;
static int remote_cache_valid
;
static int remote_instub
;
static void remote_signal();
static void remote_debug();
static int (*send_msg
)();
static int (*recv_msg
)();
static void (*closelink
)();
static u_char
*outbuffer
;
static int remote_seqerrs
;
static int remote_spurious
;
#define PUTCMD(cmd) m_xchg(cmd, (u_char *)0, 0, (u_char *)0, (int *)0)
* Send an outbound message to the remote machine and read the reply.
* Either or both message buffers may be NULL.
m_xchg(type
, out
, outlen
, in
, inlen
)
register int err
, (*send
)() = send_msg
, (*recv
)() = recv_msg
;
err
= (*send
)(type
| seqbit
, out
, outlen
);
remote_debug("send error %d\n", err
);
print_msg(type
| seqbit
, out
, outlen
, 'O');
err
= (*recv
)(&ack
, in
, inlen
);
remote_debug("recv error %d\n", err
);
print_msg(ack
, in
, inlen
? *inlen
: 0, 'I');
if ((ack
& KGDB_ACK
) == 0 || KGDB_CMD(ack
) != KGDB_CMD(type
)) {
if ((ack
& KGDB_SEQ
) ^ seqbit
) {
* Wait for the specified message type. Discard anything else.
* (this is used by 'remote-signal' to help us resync with other side.)
err
= (*recv_msg
)(&reply
, in
, inlen
);
remote_debug("recv error %d\n", err
);
print_msg(reply
, in
, inlen
? *inlen
: 0, 'I');
if (KGDB_CMD(reply
) == type
)
* Send a message. Do not wait for *any* response from the other side.
* Some other thread of control will pick up the ack that will be generated.
err
= (*send_msg
)(type
, buf
, len
);
remote_debug("[send error %d] ", err
);
print_msg(type
, buf
, len
, 'O');
* Open a connection to a remote debugger.
* NAME is the filename used for communication.
remote_open(name
, from_tty
)
if (sl_open(name
, &send_msg
, &recv_msg
, &closelink
, &remote_mtu
,
printf("Remote debugging using %s\n", name
);
inbuffer
= (u_char
*)malloc(bufsize
);
outbuffer
= (u_char
*)malloc(bufsize
);
* Close the open connection to the remote debugger. Use this when you want
* to detach and do something else with your gdb.
error("remote debugging not enabled");
* Take remote machine out of debug mode.
printf("Ending remote debugging\n");
* Tell the remote machine to resume.
remote_resume(step
, signal
)
* Wait until the remote machine stops, then return, storing status in STATUS
* When the machine stops, it will send us a KGDB_SIGNAL message,
* so we wait for one of these.
m_recv(KGDB_SIGNAL
, inbuffer
, &len
);
WSETSTOP((*status
), inbuffer
[0]);
* Register context as of last remote_fetch_registers().
static char reg_cache
[REGISTER_BYTES
];
* Read the remote registers into the block REGS.
remote_fetch_registers(regs
)
int regno
, len
, rlen
, ack
;
outbuffer
[0] = regno
+ 1;
ack
= m_xchg(remote_cache_valid
?
KGDB_REG_R
|KGDB_DELTA
: KGDB_REG_R
,
outbuffer
, 1, inbuffer
, &len
);
rlen
= REGISTER_RAW_SIZE(regno
);
®_cache
[REGISTER_BYTE(regno
)], rlen
);
} while (ack
& KGDB_MORE
);
bcopy(reg_cache
, regs
, REGISTER_BYTES
);
* Store the remote registers from the contents of the block REGS.
remote_store_registers(regs
)
for (regno
= 0; regno
< NUM_REGS
; ++regno
) {
off
= REGISTER_BYTE(regno
);
rlen
= REGISTER_RAW_SIZE(regno
);
if (!remote_cache_valid
||
bcmp(®s
[off
], ®_cache
[off
], rlen
) != 0) {
if (cp
+ rlen
+ 1 >= ep
) {
outbuffer
, cp
- outbuffer
,
bcopy(®s
[off
], cp
, rlen
);
(void)m_xchg(KGDB_REG_W
, outbuffer
, cp
- outbuffer
,
bcopy(regs
, reg_cache
, REGISTER_BYTES
);
* Store a chunk of memory into the remote host.
* 'remote_addr' is the address in the remote memory space.
* 'cp' is the address of the buffer in our space, and 'len' is
* the number of bytes. Returns an errno status.
remote_write_inferior_memory(remote_addr
, cp
, len
)
cnt
= min(len
, remote_mtu
- 4);
bcopy((char *)&remote_addr
, outbuffer
, 4);
bcopy(cp
, outbuffer
+ 4, cnt
);
(void)m_xchg(KGDB_MEM_W
, outbuffer
, cnt
+ 4, inbuffer
, &len
);
* Read memory data directly from the remote machine.
* 'remote_addr' is the address in the remote memory space.
* 'cp' is the address of the buffer in our space, and 'len' is
* the number of bytes. Returns an errno status.
remote_read_memory(remote_addr
, cp
, len
)
cnt
= min(len
, remote_mtu
- 1);
bcopy((char *)&remote_addr
, (char *)&outbuffer
[1], 4);
(void)m_xchg(KGDB_MEM_R
, outbuffer
, 5, inbuffer
, &inlen
);
error("remote_read_memory() request botched");
bcopy((char *)&inbuffer
[1], (char *)cp
, cnt
);
remote_read_inferior_memory(remote_addr
, cp
, len
)
extern CORE_ADDR text_start
, text_end
;
CORE_ADDR xferend
= remote_addr
+ len
;
if (remote_addr
< text_end
&& text_start
< xferend
) {
* at least part of this xfer is in the text
* space -- xfer the overlap from the exec file.
if (remote_addr
>= text_start
&& xferend
< text_end
)
return (xfer_core_file(remote_addr
, cp
, len
));
if (remote_addr
>= text_start
) {
int i
= text_end
- remote_addr
;
if (stat
= xfer_core_file(remote_addr
, cp
, i
))
} else if (xferend
<= text_end
) {
int i
= xferend
- text_start
;
len
= text_start
- remote_addr
;
if (stat
= xfer_core_file(text_start
,
return remote_read_memory(remote_addr
, cp
, len
);
* Signal the remote machine. The remote end might be idle or it might
* already be in debug mode -- we need to handle both case. Thus, we use
* the framing character as the wakeup byte, and send a SIGNAL packet.
* If the remote host is idle, the framing character will wake it up.
* If it is in the kgdb stub, then we will get a SIGNAL reply.
printf("Remote debugging not enabled.\n");
m_send(KGDB_SIGNAL
, (u_char
*)0, 0);
extern int stop_after_attach
;
error("Not debugging remote.");
* Print a message for debugging.
print_msg(type
, buf
, len
, dir
)
switch (KGDB_CMD(type
)) {
case KGDB_MEM_R
: s
= "memr"; break;
case KGDB_MEM_W
: s
= "memw"; break;
case KGDB_REG_R
: s
= "regr"; break;
case KGDB_REG_W
: s
= "regw"; break;
case KGDB_CONT
: s
= "cont"; break;
case KGDB_STEP
: s
= "step"; break;
case KGDB_KILL
: s
= "kill"; break;
case KGDB_SIGNAL
: s
= "sig "; break;
case KGDB_EXEC
: s
= "exec"; break;
default: s
= "unk "; break;
remote_debug("%c %c%c%c%c %s (%02x): ", dir
,
(type
& KGDB_ACK
) ? 'A' : '.',
(type
& KGDB_DELTA
) ? 'D' : '.',
(type
& KGDB_MORE
) ? 'M' : '.',
(type
& KGDB_SEQ
) ? '-' : '+',
for (i
= 0; i
< len
; ++i
)
remote_debug("%02x", buf
[i
]);
set_remote_text_refs_command(arg
, from_tty
)
icache
= !parse_binary_operation("set remote-text-refs", arg
);
remote_debug_command(arg
, from_tty
)
if (kiodebug
!= 0 && kiodebug
!= stderr
)
printf("Remote debugging off.\n");
kiodebug
= fopen(arg
, "w");
printf("Cannot open '%s'.\n", arg
);
printf("Remote debugging output routed to %s.\n", name
);
remote_info(arg
, from_tty
)
printf("Using %s for text references.\n",
icache
? "local executable" : "remote");
printf("Protocol debugging is %s.\n", kiodebug
? "on" : "off");
printf("%d spurious input messages.\n", remote_spurious
);
printf("%d input errors; %d output errors; %d sequence errors.\n",
remote_ierrs
, remote_oerrs
, remote_seqerrs
);
(void)vfprintf(kiodebug
, cp
, ap
);
extern struct cmd_list_element
*setlist
;
add_com("remote-signal", class_run
, remote_signal_command
,
"If remote debugging, send interrupt signal to remote.");
add_cmd("remote-text-refs", class_support
,
set_remote_text_refs_command
,
"Enable/disable use of local executable for text segment references.\n\
If on, all memory read/writes go to remote.\n\
If off, text segment reads use the local executable.",
add_com("remote-debug", class_run
, remote_debug_command
,
"With a file name argument, enables output of remote protocol debugging\n\
messages to said file. If file is `-', stderr is used.\n\
With no argument, remote debugging is disabled.");
add_info("remote", remote_info
,
"Show current settings of remote debugging options.");