From 27ecc2adbc0b52765d647326836e7314264bcc59 Mon Sep 17 00:00:00 2001 From: Benno Rice Date: Fri, 5 Sep 2014 16:40:47 +0000 Subject: [PATCH] Add support for gdb's memory searching capabilities to our in-kernel gdb server. Submitted by: Daniel O'Connor Reviewed by: jhb Sponsored by: EMC Isilon Storage Division --- sys/conf/files | 3 ++- sys/gdb/gdb_int.h | 3 +++ sys/gdb/gdb_main.c | 24 +++++++++++++++++ sys/gdb/gdb_packet.c | 44 +++++++++++++++++++++++++++++++ sys/libkern/memmem.c | 62 ++++++++++++++++++++++++++++++++++++++++++++ sys/sys/libkern.h | 1 + 6 files changed, 136 insertions(+), 1 deletion(-) create mode 100644 sys/libkern/memmem.c diff --git a/sys/conf/files b/sys/conf/files index b5cfa267fea0..3202c34f75cc 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -3176,8 +3176,9 @@ libkern/inet_pton.c standard libkern/jenkins_hash.c standard libkern/mcount.c optional profiling-routine libkern/memcchr.c standard -libkern/memchr.c optional fdt +libkern/memchr.c optional fdt | gdb libkern/memcmp.c standard +libkern/memmem.c optional gdb libkern/qsort.c standard libkern/qsort_r.c standard libkern/random.c standard diff --git a/sys/gdb/gdb_int.h b/sys/gdb/gdb_int.h index d06943a2a002..aa8940257a69 100644 --- a/sys/gdb/gdb_int.h +++ b/sys/gdb/gdb_int.h @@ -60,6 +60,9 @@ void gdb_tx_begin(char); int gdb_tx_end(void); int gdb_tx_mem(const unsigned char *, size_t); void gdb_tx_reg(int); +int gdb_rx_bindata(unsigned char *data, size_t datalen, size_t *amt); +int gdb_search_mem(const unsigned char *addr, size_t size, + const unsigned char *pat, size_t patlen, const unsigned char **found); static __inline void gdb_tx_char(char c) diff --git a/sys/gdb/gdb_main.c b/sys/gdb/gdb_main.c index 4ed3272108e5..f8f3836f66eb 100644 --- a/sys/gdb/gdb_main.c +++ b/sys/gdb/gdb_main.c @@ -53,6 +53,8 @@ SET_DECLARE(gdb_dbgport_set, struct gdb_dbgport); struct gdb_dbgport *gdb_cur = NULL; int gdb_listening = 0; +static unsigned char gdb_bindata[64]; + static int gdb_init(void) { @@ -254,6 +256,28 @@ gdb_trap(int type, int code) gdb_tx_begin('l'); gdb_tx_end(); } + } else if (gdb_rx_equal("Search:memory:")) { + size_t patlen; + intmax_t addr, size; + const unsigned char *found; + if (gdb_rx_varhex(&addr) || gdb_rx_char() != ';' || + gdb_rx_varhex(&size) || gdb_rx_char() != ';' || + gdb_rx_bindata(gdb_bindata, sizeof(gdb_bindata), &patlen)) { + gdb_tx_err(EINVAL); + break; + } + if (gdb_search_mem((char *)(uintptr_t)addr, size, gdb_bindata, patlen, &found)) { + if (found == 0ULL) + gdb_tx_begin('0'); + else { + gdb_tx_begin('1'); + gdb_tx_char(','); + gdb_tx_hex((intmax_t)(uintptr_t)found, 8); + } + gdb_tx_end(); + } else + gdb_tx_err(EIO); + break; } else if (!gdb_cpu_query()) gdb_tx_empty(); break; diff --git a/sys/gdb/gdb_packet.c b/sys/gdb/gdb_packet.c index a62cc8d16b36..73ee74f34bd0 100644 --- a/sys/gdb/gdb_packet.c +++ b/sys/gdb/gdb_packet.c @@ -31,6 +31,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include @@ -320,3 +321,46 @@ gdb_tx_reg(int regnum) } else gdb_tx_mem(regp, regsz); } + +/* Read binary data up until the end of the packet or until we have datalen decoded bytes */ +int +gdb_rx_bindata(unsigned char *data, size_t datalen, size_t *amt) +{ + int c; + + *amt = 0; + + while (*amt < datalen) { + c = gdb_rx_char(); + /* End of packet? */ + if (c == -1) + break; + /* Escaped character up next */ + if (c == '}') { + /* Truncated packet? Bail out */ + if ((c = gdb_rx_char()) == -1) + return (1); + c ^= 0x20; + } + *(data++) = c & 0xff; + (*amt)++; + } + + return (0); +} + +int +gdb_search_mem(const unsigned char *addr, size_t size, const unsigned char *pat, size_t patlen, const unsigned char **found) +{ + void *prev; + jmp_buf jb; + int ret; + + prev = kdb_jmpbuf(jb); + ret = setjmp(jb); + if (ret == 0) + *found = memmem(addr, size, pat, patlen); + + (void)kdb_jmpbuf(prev); + return ((ret == 0) ? 1 : 0); +} diff --git a/sys/libkern/memmem.c b/sys/libkern/memmem.c new file mode 100644 index 000000000000..9c6e0d162eb1 --- /dev/null +++ b/sys/libkern/memmem.c @@ -0,0 +1,62 @@ +/*- + * Copyright (c) 2005 Pascal Gloor + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 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. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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 + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include + +void * +memmem(const void *l, size_t l_len, const void *s, size_t s_len) +{ + register char *cur, *last; + const char *cl = (const char *)l; + const char *cs = (const char *)s; + + /* we need something to compare */ + if (l_len == 0 || s_len == 0) + return NULL; + + /* "s" must be smaller or equal to "l" */ + if (l_len < s_len) + return NULL; + + /* special case where s_len == 1 */ + if (s_len == 1) + return memchr(l, (int)*cs, l_len); + + /* the last position where its possible to find "s" in "l" */ + last = (char *)cl + l_len - s_len; + + for (cur = (char *)cl; cur <= last; cur++) + if (cur[0] == cs[0] && memcmp(cur, cs, s_len) == 0) + return cur; + + return NULL; +} diff --git a/sys/sys/libkern.h b/sys/sys/libkern.h index 5f850fb2da85..ec5f761e7a86 100644 --- a/sys/sys/libkern.h +++ b/sys/sys/libkern.h @@ -103,6 +103,7 @@ int locc(int, char *, u_int); void *memchr(const void *s, int c, size_t n); void *memcchr(const void *s, int c, size_t n); int memcmp(const void *b1, const void *b2, size_t len); +void *memmem(const void *l, size_t l_len, const void *s, size_t s_len); void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *)); void qsort_r(void *base, size_t nmemb, size_t size, void *thunk,