Implements a small breakpoint lib

Allows to store & efficient lookup
This commit is contained in:
Yann Weber 2023-04-03 19:35:34 +02:00
commit e3d0baa414
4 changed files with 354 additions and 1 deletions

View file

@ -1,6 +1,6 @@
bin_PROGRAMS = asmsh child 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 \ completion.c shell.c shell_cmds.c shell_sym.c \
history.c history.c

175
breakpoints.c Normal file
View file

@ -0,0 +1,175 @@
/* Copyright Yann Weber <asmsh@yannweb.net>
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 <https://www.gnu.org/licenses/>.
*/
#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;
}

70
breakpoints.h Normal file
View file

@ -0,0 +1,70 @@
/* Copyright Yann Weber <asmsh@yannweb.net>
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 <https://www.gnu.org/licenses/>.
*/
#ifndef ASMSH_BREAKPOINTS_H
#define ASMSH_BREAKPOINTS_H
#include "config.h"
#include <errno.h>
#include <stdlib.h>
#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

108
tests/tests_breakpoints.c Normal file
View file

@ -0,0 +1,108 @@
#include "config.h"
#include <check.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#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