diff --git a/Makefile.am b/Makefile.am index df4a085..eaf642c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,6 +1,6 @@ bin_PROGRAMS = asmsh child -libcheck_asmsh_a_SOURCES = mmap_parse.c asm_env.c compile.c logger.c \ +libcheck_asmsh_a_SOURCES = mmap_parse.c asm_env.c breakpoints.c compile.c logger.c \ completion.c shell.c shell_cmds.c shell_sym.c \ history.c diff --git a/breakpoints.c b/breakpoints.c new file mode 100644 index 0000000..01f7fa8 --- /dev/null +++ b/breakpoints.c @@ -0,0 +1,175 @@ +/* Copyright Yann Weber + This file is part of asmsh. + + asmsh is free software: you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation, either version 3 of the License, or any later version. + + asmsh is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + details. + + You should have received a copy of the GNU General Public License along + with asmsh. If not, see . +*/ +#include "breakpoints.h" + +/** Efficient search of a breakpoint address + * + * @param brks pointer on the breakpoint list + * @param addr the address to search + * @param idx a pointer on the breakpoint index + * @return -1 if not found else 0 + * + * @note idx is set to a value suitable for insertion if value is not found + */ +static int asmsh_brk_index(asmsh_brk_t *brks, unsigned long addr, size_t *idx); + + +int asmsh_brk_init(asmsh_brk_t *brks) +{ + brks->addrs = NULL; + brks->sz = 0; + + return 0; +} + + +void asmsh_brk_free(asmsh_brk_t *brks) +{ + free(brks->addrs); +} + + +int asmsh_brk_add(asmsh_brk_t *brks, unsigned long addr) +{ + size_t idx; + int ret; + + void *tmp; + + ret = asmsh_brk_index(brks, addr, &idx); + + if(ret == 0) + { + return 1; + } + if(brks->sz > 0) + { + tmp = realloc(brks->addrs, sizeof(*brks->addrs)*(brks->sz + 1)); + if(tmp == NULL) + { + int err = errno; + asmsh_log_perror("Unable to reallocate breakpoint list"); + errno = err; + return -1; + } + brks->addrs=tmp; + } + else + { + if(!(brks->addrs = malloc(sizeof(*brks->addrs)))) + { + int err = errno; + asmsh_log_perror("Unable to allocate breakpoint list"); + errno = err; + return -1; + } + } + if(idx == brks->sz) + { + brks->addrs[brks->sz] = addr; + } + else + { + memmove(&(brks->addrs[idx+1]),&(brks->addrs[idx]), + (brks->sz - idx)*sizeof(*brks->addrs)); + brks->addrs[idx] = addr; + } + brks->sz++; + return 0; +} + +int asmsh_brk_del(asmsh_brk_t *brks, unsigned long addr) +{ + size_t idx; + int ret; + + void *tmp; + + ret = asmsh_brk_index(brks, addr, &idx); + + if(ret < 0) + { + return 1; + } + brks->sz--; + if(idx < brks->sz) + { + memmove(&(brks->addrs[idx]), &(brks->addrs[idx+1]), + sizeof(*brks->addrs)*brks->sz); + } + if(brks->sz) + { + tmp = realloc(brks->addrs, brks->sz); + if(tmp == NULL) + { + int err = errno; + asmsh_log_perror("Unable to reallocate breakpoint list when removing"); + errno = err; + return -1; + } + brks->addrs=tmp; + } + else + { + free(brks->addrs); + brks->addrs = NULL; + } + return 0; +} + +int asmsh_brk_isset(asmsh_brk_t *brks, unsigned long addr) +{ + size_t idx; + return asmsh_brk_index(brks, addr, &idx) == 0; +} + +static int asmsh_brk_index(asmsh_brk_t *brks, unsigned long addr, size_t *idx) +{ + size_t beg, end, mid; + + if(brks->sz == 0) + { + *idx = 0; + return -1; + } + + beg = 0; + end = brks->sz; + + while(end >= beg) + { + mid = (beg + end) / 2; + if(brks->addrs[mid] == addr) + { + *idx = mid; + return 0; + } + else if(brks->addrs[mid] > addr) + { + if(mid == 0) { break; } + end = mid - 1; + } + else + { + beg = mid + 1; + if(beg >= brks->sz) { break; } + } + } + *idx = beg; + return -1; + +} + diff --git a/breakpoints.h b/breakpoints.h new file mode 100644 index 0000000..499b365 --- /dev/null +++ b/breakpoints.h @@ -0,0 +1,70 @@ +/* Copyright Yann Weber + This file is part of asmsh. + + asmsh is free software: you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation, either version 3 of the License, or any later version. + + asmsh is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + details. + + You should have received a copy of the GNU General Public License along + with asmsh. If not, see . +*/ +#ifndef ASMSH_BREAKPOINTS_H +#define ASMSH_BREAKPOINTS_H +#include "config.h" + +#include +#include + +#include "logger.h" + +typedef struct asmsh_brk_s asmsh_brk_t; + + +/** Stores breakpoints informations */ +struct asmsh_brk_s +{ + /** Breakpoint addresses sorted ascending */ + unsigned long *addrs; + /** Number of breakpoints */ + size_t sz; +}; + +/** Initialize the breakpoint list + * @param brks Pointer on the list to initialize + * @return 0 if no error else -1 + */ +int asmsh_brk_init(asmsh_brk_t *brks); + +/** Cleanup a breakpoint list struct + * @param brks Pointer on the list to clean + */ +void asmsh_brk_free(asmsh_brk_t *brks); + +/** Add a breakpoint + * @param brks Pointer on the list + * @param addr The breakpoint's address + * @return 0 if no error 1 if allready present else -1 and set errno + */ +int asmsh_brk_add(asmsh_brk_t *brks, unsigned long addr); + +/** Del a breakpoint + * @param brks Pointer on the list + * @param addr The breakpoint's address + * @return 0 if no error 1 if not present else -1 and set errno + */ +int asmsh_brk_del(asmsh_brk_t *brks, unsigned long addr); + +/** Check if a breakpoint exists + * @param brks Pointer on the list + * @param addr The address to check + * @return 0 if no breakpoint at given address + */ +int asmsh_brk_isset(asmsh_brk_t *brks, unsigned long addr); + +#endif + diff --git a/tests/tests_breakpoints.c b/tests/tests_breakpoints.c new file mode 100644 index 0000000..5bc3062 --- /dev/null +++ b/tests/tests_breakpoints.c @@ -0,0 +1,108 @@ +#include "config.h" + +#include +#include +#include +#include +#include + +#include "asmsh_check.h" +#include "breakpoints.h" + +START_TEST(brk_add) +{ + asmsh_brk_t brks; + asmsh_brk_init(&brks); + ck_assert_int_eq(brks.sz, 0); + + ck_assert_int_eq(asmsh_brk_add(&brks, 0x42), 0); + ck_assert_int_eq(brks.sz, 1); + ck_assert_int_eq(brks.addrs[0], 0x42); + ck_assert_int_eq(asmsh_brk_add(&brks, 0x42), 1); + ck_assert_int_eq(asmsh_brk_add(&brks, 0x1312), 0); + ck_assert_int_eq(brks.sz, 2); + ck_assert_int_eq(brks.addrs[0], 0x42); + ck_assert_int_eq(brks.addrs[1], 0x1312); +} +END_TEST + +START_TEST(brk_add_order) +{ + asmsh_brk_t brks; + asmsh_brk_init(&brks); + + for(int s=0;s<2;s++) + { + for(int i=s;i<10; i+=2) + { + ck_assert_int_eq(asmsh_brk_add(&brks, i), 0); + } + } + for(int i=0;i<10;i++) + { + ck_assert_int_eq(brks.addrs[i], i); + } +} + +START_TEST(brk_isset) +{ + asmsh_brk_t brks; + asmsh_brk_init(&brks); + ck_assert_int_eq(brks.sz, 0); + + ck_assert_int_eq(asmsh_brk_isset(&brks, 0x42), 0); + ck_assert_int_eq(asmsh_brk_isset(&brks, 0x1312), 0); + ck_assert_int_eq(asmsh_brk_add(&brks, 0x42), 0); + ck_assert_int_ne(asmsh_brk_isset(&brks, 0x42), 0); + + ck_assert_int_eq(asmsh_brk_add(&brks, 0x1312), 0); +dprintf(2,"test isset\n"); + ck_assert_int_ne(asmsh_brk_isset(&brks, 0x1312), 0); +dprintf(2,"test isset2\n"); + ck_assert_int_ne(asmsh_brk_isset(&brks, 0x42), 0); +} +END_TEST + + +START_TEST(brk_del) +{ + asmsh_brk_t brks; + asmsh_brk_init(&brks); + ck_assert_int_eq(brks.sz, 0); + + ck_assert_int_eq(asmsh_brk_add(&brks, 0x42), 0); + ck_assert_int_eq(asmsh_brk_add(&brks, 0x1312), 0); + ck_assert_int_ne(asmsh_brk_isset(&brks, 0x42), 0); + ck_assert_int_ne(asmsh_brk_isset(&brks, 0x1312), 0); + + ck_assert_int_eq(asmsh_brk_del(&brks, 0x42), 0); + ck_assert_int_eq(asmsh_brk_isset(&brks, 0x42), 0); + ck_assert_int_ne(asmsh_brk_isset(&brks, 0x1312), 0); + + ck_assert_int_eq(asmsh_brk_del(&brks, 0x42), 1); + ck_assert_int_eq(asmsh_brk_isset(&brks, 0x42), 0); + ck_assert_int_ne(asmsh_brk_isset(&brks, 0x1312), 0); + + ck_assert_int_eq(asmsh_brk_del(&brks, 0x1312), 0); + ck_assert_int_eq(asmsh_brk_isset(&brks, 0x42), 0); + ck_assert_int_eq(asmsh_brk_isset(&brks, 0x1312), 0); +} +END_TEST + + + +/* +START_TEST(brk_) +{ + asmsh_brk_t brks; + asmsh_brk_init(&brks); +} +END_TEST +*/ + +ASMSH_CHECK_START("Testing breakpoints lib", "Testing breakpoints manipulation") + ASMSH_ADD_TEST(brk_add); + ASMSH_ADD_TEST(brk_add_order); + ASMSH_ADD_TEST(brk_isset); + ASMSH_ADD_TEST(brk_del); +ASMSH_CHECK_END