All instructions can be traducted "on-the-fly". (except FPU instruction because

they do not exist on SH3 mpu based).
Write "driver" for getkey Casio's function for get the key's "status" (caps-lock, letter, number).
Add commands and modes handling.
Add somes commands.
Add somes units tests.
This commit is contained in:
yann MAGNIN 2019-06-10 02:14:49 +02:00
parent 441e57ee53
commit 7a0e037705
38 changed files with 4174 additions and 0 deletions

3
.gitignore vendored
View File

@ -52,3 +52,6 @@ Module.symvers
Mkfile.old
dkms.conf
# Other
*.txt
build/

90
Makefile Normal file
View File

@ -0,0 +1,90 @@
#!/usr/bin/make -f
# ---
# Project: FIXME WRITE DOC !!
# Author: yann.magnin@epitech.eu
# ---
include global.mk
NAME := dump
EXEC := $(NAME).g1a
HEADER := -Iinclude
DEBUG := link_map.txt
LDFLAG := -T bootstrap.ld
ICON := icon.bmp
BUILD := build/
SRC :=
DIRECTORY := src/ $(sort $(dir $(wildcard src/*/*/)))
$(foreach path,$(DIRECTORY),$(eval \
SRC += $(wildcard $(path)*.c) \
$(wildcard $(path)*.s) \
$(wildcard $(path)*.S)) \
)
OBJ := $(patsubst src_%,$(BUILD)%.o,$(subst /,_,$(basename $(SRC))))
#all: ;@echo $(SRC) $(OBJ)
all: | $(BUILD) $(EXEC)
install: $(EXEC)
sudo p7 send $<
$(EXEC): $(OBJ)
@ printf "$(green)/-------\n/ Link files\n/-------$(nocolor)\n"
$(CC) -Wl,-M $(LDFLAG) $(CFLAGS) -o $(BUILD)$(NAME).elf $^ $(HEADER) -lgcc > $(DEBUG)
$(OBJCPY) -R .comment -R .bss -O binary $(BUILD)$(NAME).elf $(BUILD)$(NAME).bin
$(WRAPPER) $(BUILD)$(NAME).bin -o $@ -i $(ICON)
$(BUILD):
@ printf "Create $(blue)$@$(nocolor) directory\n"
@ mkdir -p $@
#
# TODO: find better way to do the job
# Units tests part.
#
tests:
gcc -std=c11 -Wall -Wno-error=deprecated-declarations -Wno-deprecated-declarations \
-Werror -D DEBUG -o unit_tests $(HEADER) -I. src/history.c src/string/strtotab.c \
src/string/atoi_base.c $(wildcard tests/*.c) --coverage -lcriterion
./unit_tests
gcovr --exclude tests/ --branches
rm *.gc*
rm ./unit_tests
define rule-src
$(patsubst src_%,$(BUILD)%.o,$(subst /,_,$(basename $1))): $1
@ printf "compiling $(white)$$<$(nocolor)..."
@ $(CC) $(CFLAGS) -o $$@ -c $$< $(HEADER) -lgcc
@ printf "$(green)[ok]$(nocolor)\n"
endef
$(foreach source,$(SRC),$(eval \
$(call rule-src,$(source))) \
)
#---
# Clean rules
#---
clean:
@ printf "$(red)Delete objects files$(nocolor)\n"
rm -rf $(BUILD)
rm -f *.gc*
rm -f $(DEBUG)
fclean: clean
@ printf "$(red)Delete binary files$(nocolor)\n"
rm -f $(EXEC)
rm -f $(NAME).bin
rm -f $(NAME).elf
re: fclean all install
.PHONY: clean re fclean install tests

48
bootstrap.ld Normal file
View File

@ -0,0 +1,48 @@
OUTPUT_ARCH(sh3)
OUTPUT_FORMAT(elf32-sh)
ENTRY(_initialize)
MEMORY
{
rom : o = 0x00300200, l = 512k
ram : o = 0x08100000, l = 8k
}
SECTIONS
{
. = ORIGIN(rom);
.pretext : {
*(.pretext.entry)
*(.pretext)
} > rom
.text : {
*(.text)
} > rom
.rodata : SUBALIGN(4) {
*(.rodata)
} > rom
. = ORIGIN(ram);
.bss (NOLOAD) : {
_bbss = . ;
*(.bss)
*(COMMON)
} > ram : NONE
_sbss = SIZEOF(.bss);
.data ALIGN(4) : ALIGN(4) {
_bdata_rom = LOADADDR(.data) ;
_bdata_ram = . ;
*(.data)
} > ram AT> rom
_sdata = SIZEOF(.data) ;
/* unused sections */
/DISCARD/ : {
*(.comment)
*(.comment.*)
}
}

27
global.mk Normal file
View File

@ -0,0 +1,27 @@
# Global options, used in each Makefile in the project
# If you have to change a tool name, or to add an option
# for every part of the project, this is the good place.
COMPILER := sh3eb-elf-
CC := $(COMPILER)gcc
OBJCPY := $(COMPILER)objcopy
AR := $(COMPILER)ar
LD := $(COMPILER)ld
WRAPPER := g1a-wrapper
CFLAGS := -Werror -Wall -W -Wextra -std=c18 -m3 -mb -mrenesas \
-ffreestanding -nostdlib -fstrict-volatile-bitfields
BUILD-DIR := build/
SRC-DIR := src/
red := \033[1;31m
green := \033[1;32m
blue := \033[1;34m
white := \033[1;37m
nocolor := \033[1;0m
define n
# Force new line character
endef

BIN
icon.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

35
include/commands.h Normal file
View File

@ -0,0 +1,35 @@
#ifndef __COMMANDS_H__
# define __COMMANDS_H__
#include <stddef.h>
#include <stdint.h>
#include <utils.h>
//FIXME: MOVE ME !
struct cmd_info
{
char *name;
struct {
ptrdiff_t anchor;
size_t size;
} update;
void (*init)(int argc, char **argv, struct session_s *session, char *info);
};
#define CMDBLOCK(bname,cmd,ptr,sizez,callback) \
static const struct cmd_info bname = { \
.name = cmd, \
.update = { \
.anchor = (ptrdiff_t)(ptr), \
.size = sizez, \
}, \
.init = callback \
}
//TODO: write doc.
void command_entry(struct session_s *session, struct dump_s *dump);
void address_jump(int argc, char **argv, struct session_s *session, char *info);
void syscall_jump(int argc, char **argv, struct session_s *session, char *info);
void ram_jump(int argc, char **argv, struct session_s *session, char *info);
void vbr_jump(int arc, char **argv, struct session_s *session, char *info);
#endif /*__COMMANDS_H__*/

156
include/errno.h Normal file
View File

@ -0,0 +1,156 @@
#ifndef __KERNEL_ERRNO_H__
# define __KERNEL_ERRNO_H__ 1
#define EPERM 1 /* Operation not permitted */
#define ENOENT 2 /* No such file or directory */
#define ESRCH 3 /* No such process */
#define EINTR 4 /* Interrupted system call */
#define EIO 5 /* I/O error */
#define ENXIO 6 /* No such device or address */
#define E2BIG 7 /* Argument list too long */
#define ENOEXEC 8 /* Exec format error */
#define EBADF 9 /* Bad file number */
#define ECHILD 10 /* No child processes */
#define EAGAIN 11 /* Try again */
#define ENOMEM 12 /* Out of memory */
#define EACCES 13 /* Permission denied */
#define EFAULT 14 /* Bad address */
#define ENOTBLK 15 /* Block device required */
#define EBUSY 16 /* Device or resource busy */
#define EEXIST 17 /* File exists */
#define EXDEV 18 /* Cross-device link */
#define ENODEV 19 /* No such device */
#define ENOTDIR 20 /* Not a directory */
#define EISDIR 21 /* Is a directory */
#define EINVAL 22 /* Invalid argument */
#define ENFILE 23 /* File table overflow */
#define EMFILE 24 /* Too many open files */
#define ENOTTY 25 /* Not a typewriter */
#define ETXTBSY 26 /* Text file busy */
#define EFBIG 27 /* File too large */
#define ENOSPC 28 /* No space left on device */
#define ESPIPE 29 /* Illegal seek */
#define EROFS 30 /* Read-only file system */
#define EMLINK 31 /* Too many links */
#define EPIPE 32 /* Broken pipe */
#define EDOM 33 /* Math argument out of domain of func */
#define ERANGE 34 /* Math result not representable */
#define EDEADLK 35 /* Resource deadlock would occur */
#define ENAMETOOLONG 36 /* File name too long */
#define ENOLCK 37 /* No record locks available */
/*
* This error code is special: arch syscall entry code will return
* -ENOSYS if users try to call a syscall that doesn't exist. To keep
* failures of syscalls that really do exist distinguishable from
* failures due to attempts to use a nonexistent syscall, syscall
* implementations should refrain from returning -ENOSYS.
*/
#define ENOSYS 38 /* Invalid system call number */
#define ENOTEMPTY 39 /* Directory not empty */
#define ELOOP 40 /* Too many symbolic links encountered */
#define EWOULDBLOCK EAGAIN /* Operation would block */
#define ENOMSG 42 /* No message of desired type */
#define EIDRM 43 /* Identifier removed */
#define ECHRNG 44 /* Channel number out of range */
#define EL2NSYNC 45 /* Level 2 not synchronized */
#define EL3HLT 46 /* Level 3 halted */
#define EL3RST 47 /* Level 3 reset */
#define ELNRNG 48 /* Link number out of range */
#define EUNATCH 49 /* Protocol driver not attached */
#define ENOCSI 50 /* No CSI structure available */
#define EL2HLT 51 /* Level 2 halted */
#define EBADE 52 /* Invalid exchange */
#define EBADR 53 /* Invalid request descriptor */
#define EXFULL 54 /* Exchange full */
#define ENOANO 55 /* No anode */
#define EBADRQC 56 /* Invalid request code */
#define EBADSLT 57 /* Invalid slot */
#define EDEADLOCK EDEADLK
#define EBFONT 59 /* Bad font file format */
#define ENOSTR 60 /* Device not a stream */
#define ENODATA 61 /* No data available */
#define ETIME 62 /* Timer expired */
#define ENOSR 63 /* Out of streams resources */
#define ENONET 64 /* Machine is not on the network */
#define ENOPKG 65 /* Package not installed */
#define EREMOTE 66 /* Object is remote */
#define ENOLINK 67 /* Link has been severed */
#define EADV 68 /* Advertise error */
#define ESRMNT 69 /* Srmount error */
#define ECOMM 70 /* Communication error on send */
#define EPROTO 71 /* Protocol error */
#define EMULTIHOP 72 /* Multihop attempted */
#define EDOTDOT 73 /* RFS specific error */
#define EBADMSG 74 /* Not a data message */
#define EOVERFLOW 75 /* Value too large for defined data type */
#define ENOTUNIQ 76 /* Name not unique on network */
#define EBADFD 77 /* File descriptor in bad state */
#define EREMCHG 78 /* Remote address changed */
#define ELIBACC 79 /* Can not access a needed shared library */
#define ELIBBAD 80 /* Accessing a corrupted shared library */
#define ELIBSCN 81 /* .lib section in a.out corrupted */
#define ELIBMAX 82 /* Attempting to link in too many shared libraries */
#define ELIBEXEC 83 /* Cannot exec a shared library directly */
#define EILSEQ 84 /* Illegal byte sequence */
#define ERESTART 85 /* Interrupted system call should be restarted */
#define ESTRPIPE 86 /* Streams pipe error */
#define EUSERS 87 /* Too many users */
#define ENOTSOCK 88 /* Socket operation on non-socket */
#define EDESTADDRREQ 89 /* Destination address required */
#define EMSGSIZE 90 /* Message too long */
#define EPROTOTYPE 91 /* Protocol wrong type for socket */
#define ENOPROTOOPT 92 /* Protocol not available */
#define EPROTONOSUPPORT 93 /* Protocol not supported */
#define ESOCKTNOSUPPORT 94 /* Socket type not supported */
#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */
#define ENOTSUP EOPNOTSUPP /* Not supported (may be the same value as [EOPNOTSUPP]) */
#define EPFNOSUPPORT 96 /* Protocol family not supported */
#define EAFNOSUPPORT 97 /* Address family not supported by protocol */
#define EADDRINUSE 98 /* Address already in use */
#define EADDRNOTAVAIL 99 /* Cannot assign requested address */
#define ENETDOWN 100 /* Network is down */
#define ENETUNREACH 101 /* Network is unreachable */
#define ENETRESET 102 /* Network dropped connection because of reset */
#define ECONNABORTED 103 /* Software caused connection abort */
#define ECONNRESET 104 /* Connection reset by peer */
#define ENOBUFS 105 /* No buffer space available */
#define EISCONN 106 /* Transport endpoint is already connected */
#define ENOTCONN 107 /* Transport endpoint is not connected */
#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */
#define ETOOMANYREFS 109 /* Too many references: cannot splice */
#define ETIMEDOUT 110 /* Connection timed out */
#define ECONNREFUSED 111 /* Connection refused */
#define EHOSTDOWN 112 /* Host is down */
#define EHOSTUNREACH 113 /* No route to host */
#define EALREADY 114 /* Operation already in progress */
#define EINPROGRESS 115 /* Operation now in progress */
#define ESTALE 116 /* Stale file handle */
#define EUCLEAN 117 /* Structure needs cleaning */
#define ENOTNAM 118 /* Not a XENIX named type file */
#define ENAVAIL 119 /* No XENIX semaphores available */
#define EISNAM 120 /* Is a named type file */
#define EREMOTEIO 121 /* Remote I/O error */
#define EDQUOT 122 /* Quota exceeded */
#define ENOMEDIUM 123 /* No medium found */
#define EMEDIUMTYPE 124 /* Wrong medium type */
#define ECANCELED 125 /* Operation Canceled */
#define ENOKEY 126 /* Required key not available */
#define EKEYEXPIRED 127 /* Key has expired */
#define EKEYREVOKED 128 /* Key has been revoked */
#define EKEYREJECTED 129 /* Key was rejected by service */
/* for robust mutexes */
#define EOWNERDEAD 130 /* Owner died */
#define ENOTRECOVERABLE 131 /* State not recoverable */
#define ERFKILL 132 /* Operation not possible due to RF-kill */
#define EHWPOISON 133 /* Memory page has hardware error */
#endif /* __KERNEL_ERRNO_H__ */

21
include/history.h Normal file
View File

@ -0,0 +1,21 @@
#ifndef __HISTORY_H__
# define __HISTORY_H__
#include <types.h>
struct node
{
const char data[32];
struct node *next;
};
struct history_s {
struct node *list;
off_t offset;
size_t deep;
};
int history_update(struct node **list, const char *data);
const void *history_get(struct node *list, off_t offset);
void history_quit(struct node **list);
#endif /*__HISTORY_H__*/

2290
include/opcode.h Normal file

File diff suppressed because it is too large Load Diff

28
include/string.h Normal file
View File

@ -0,0 +1,28 @@
#ifndef __STRING_H__
# define __STRING_H__
#include <types.h>
#include <stdarg.h>
#define WEAK __attribute__((weak))
//#ifndef DEBUG
WEAK void *memset(void *s, int c, size_t n);
#ifndef DEBUG
WEAK void vsprintf(char *str, char const *format, va_list ap);
WEAK void sprintf(char *str, char const *format, ...);
#endif /* DEBUG */
WEAK char *strcat(char *dest, char const *src);
WEAK int strcmp(const char *s1, const char *s2);
WEAK char *strncpy(char *dest, char const *str, size_t size);
WEAK char *strcpy(char *dest, char const *src);
WEAK size_t strlen(char const *str);
// Custom functions
int strtotab(int *argc, char ***argv, char const *str);
void strtotab_quit(int *argc, char ***argv);
uint32_t atoi_base(char const *str, int base);
//#endif /* DEBUG */
#endif /*__STRING_H__*/

42
include/syscalls.h Normal file
View File

@ -0,0 +1,42 @@
#ifndef __CASIO_H__
# define __CASIO_H__
#include <types.h>
struct rect
{
int left;
int top;
int right;
int bottom;
};
// Casio prototype.
void casio_GetKey(unsigned int *key);
void casio_Bdisp_AllClr_DDVRAM(void);
void casio_Bdisp_AreaClr_DDVRAM(const struct rect *buf);
void casio_PrintMini(size_t x, size_t y, char const *str, int mode);
void casio_Bdisp_DrawLine_VRAM(int x1, int y1, int x2, int y2);
void casio_RestoreDisp(unsigned char page);
void casio_SaveDisp(unsigned char page);
void *casio_Malloc(size_t size);
void *casio_Free(void *ptr);
// Internal casio abstraction.
static INLINE void dclear_area(int x1, int y1, int x2, int y2)
{
struct rect area = {.left = x1, .top = y1, .right = x2, .bottom = y2};
casio_Bdisp_AreaClr_DDVRAM(&area);
}
#define print(x, y, str) casio_PrintMini(x, y, str, 0)
#define getkey casio_GetKey
#define dline_horizontal(y, x1, x2) casio_Bdisp_DrawLine_VRAM(x1, y, x2, y)
#define dclear casio_Bdisp_AllClr_DDVRAM
#define save_window casio_SaveDisp
#define restore_window casio_RestoreDisp
#define malloc casio_Malloc
#define free casio_Free
#endif /*__CASIO_H__*/

21
include/types.h Normal file
View File

@ -0,0 +1,21 @@
#ifndef __TYPES_H__
# define __TYPES_H__
#include <stddef.h>
#include <stdint.h>
//TODO: write doc
# ifndef __off_t_defined
typedef uint32_t off_t;
# define __off_t_defined
# endif
#ifndef __ssize_t_defined
typedef int32_t ssize_t;
# define __ssize_t_defined
#endif
#define INLINE __attribute__((always_inline)) inline
#endif /*__TYPES_H__*/

124
include/utils.h Normal file
View File

@ -0,0 +1,124 @@
#ifndef __UTILS_H__
# define __UTILS_H__
#include <types.h>
#include <history.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define FONT_WIDTH 4
#define FONT_HEIGHT 6
#define LINE_OFFSET ((SCREEN_HEIGHT / FONT_HEIGHT) - 1)
#define COLUMN_OFFSET (SCREEN_WIDTH / FONT_WIDTH)
#define KEY_UP 30018
#define KEY_DOWN 30023
#define KEY_LEFT 30020
#define KEY_RIGHT 30021
#define KEY_OPTN 30008
#define KEY_F1 30009
#define KEY_F2 30010
#define KEY_F3 30011
#define KEY_F4 30012
#define KEY_F5 30013
#define KEY_F6 30014
#define KEY_SHIFT 30006
#define KEY_ALPHA 30007
#define KEY_ENTER 30004
#define KEY_DEL 30025
#define KEY_SPACE 0x20
#define KEY_INS 30033
#define KEY_PI 0xd0
#define KEY_QUOTE KEY_PI
#define KEY_A 0x41
#define KEY_B 0x42
#define KEY_C 0x43
#define KEY_D 0x44
#define KEY_E 0x45
#define KEY_F 0x46
#define KEY_G 0x47
#define KEY_H 0x48
#define KEY_I 0x49
#define KEY_J 0x4a
#define KEY_K 0x4b
#define KEY_L 0x4c
#define KEY_M 0x4d
#define KEY_N 0x4e
#define KEY_O 0x4f
#define KEY_P 0x50
#define KEY_Q 0x51
#define KEY_R 0x52
#define KEY_S 0x53
#define KEY_T 0x54
#define KEY_U 0x55
#define KEY_V 0x56
#define KEY_W 0x57
#define KEY_X 0x58
#define KEY_Y 0x59
#define KEY_Z 0x5a
#define KEY_0 0x30
#define KEY_1 0x31
#define KEY_2 0x32
#define KEY_3 0x33
#define KEY_4 0x34
#define KEY_5 0x35
#define KEY_6 0x36
#define KEY_7 0x37
#define KEY_8 0x38
#define KEY_9 0x39
#define ARGUMENTS_MAX 3
#define INSTRUCTION_SIZE 2
#define SESSIONS_SLOT 6
#define CMD_LENGHT_MAX 15
enum mode_e
{
UNUSED,
COMMAND,
NORMAL,
FREE
};
struct session_s
{
enum mode_e mode;
ptrdiff_t anchor;
off_t cursor;
size_t size;
};
enum insert_mode
{
LETTER,
CAPS_LOCK,
NUMBER,
SHIFT
};
struct dump_s
{
int current_session;
struct session_s session[SESSIONS_SLOT];
struct {
char backup[CMD_LENGHT_MAX];
char cmd[CMD_LENGHT_MAX];
enum insert_mode mode;
} insert;
char info[CMD_LENGHT_MAX];
struct history_s history;
};
// screen part.
void dclear(void);
void dupdate(void);
void display_instructions(const struct session_s *session);
void display_metainfos(const struct dump_s *dump, const struct session_s *session);
void key_handling(struct dump_s *dump, struct session_s *session, unsigned int key);
#endif /*__UTILS_H__*/

56
src/boot/crt0.c Normal file
View File

@ -0,0 +1,56 @@
#include <stdint.h>
#include <stddef.h>
extern int main(void);
//define by bootstrap.ld
extern uint32_t bbss;
extern uint32_t sbss;
extern uint32_t bdata_rom;
extern uint32_t bdata_ram;
extern uint32_t sdata;
//
// section_dump()
// copy a memory region using symbol information.
//
__attribute__((section(".pretext")))
void section_dump(uint32_t * restrict dest, uint32_t * restrict load, size_t size)
{
size_t i;
i = -1;
while (++i < size >> 2)
dest[i] = load[i];
}
//
// section_reset()
// clear a memory region using symbol information.
//
__attribute__((section(".pretext")))
void section_reset(uint32_t *bsection, size_t size)
{
size_t i;
i = -1;
while (++i < size >> 2)
bsection[i] = 0;
}
//
// initialize()
// We are currently running in the storage memory, so we should
// load data in RAM and wipe the bss section for initialize static
// and global variables.
//
__attribute__((section(".pretext.entry")))
int initialize(void)
{
int exit;
section_reset(&bbss, (size_t)&sbss);
section_dump(&bdata_ram, &bdata_rom, (size_t)&sdata);
exit = main();
return (exit);
}

View File

@ -0,0 +1,19 @@
#include <commands.h>
#include <string.h>
static INLINE int check_address(char *str)
{
--str;
while ((*(++str) >= '0' && *str <= '9') || (*str >= 'a' && *str <= 'f'));
return ((*str != '\0') ? 1 : 0);
}
void address_jump(int argc, char **argv, struct session_s *session, char *info)
{
if (argc != 2 || check_address(argv[1]) != 0){
strcpy(info, "arguments error");
return;
}
session->anchor = atoi_base(argv[1], 16) >> 1 << 1;
session->size = 0xffffffff;
}

61
src/commands/entry.c Normal file
View File

@ -0,0 +1,61 @@
#include <commands.h>
#include <string.h>
#include <errno.h>
CMDBLOCK(rom, "rom", 0x00300200, 0xffffffff, NULL);
CMDBLOCK(systab, "systab", 0x80010070, 0xffffffff, NULL);
CMDBLOCK(ram, "ram", NULL, 0xffffffff, &ram_jump);
CMDBLOCK(vbrjmp, "vbrjmp", NULL, 0xffffffff, &vbr_jump);
CMDBLOCK(addr_jump, "jmp", NULL, 0xffffffff, &address_jump);
CMDBLOCK(sysc_jump, "syscall", NULL, 0xffffffff, &syscall_jump);
//TODO:
// - dynamique allocation cache.
// - rename function.
static int find_command(int argc, char **argv, struct session_s *session,
struct dump_s *dump)
{
static const struct cmd_info *cache[] = {
&addr_jump, &vbrjmp, &systab, &sysc_jump, &ram, &rom, NULL
};
size_t i;
i = -1;
while (cache[++i] != NULL && strcmp(cache[i]->name, *argv));
if (cache[i] == NULL)
return (EBADMSG);
if (cache[i]->init == NULL){
session->cursor = 0;
session->anchor = cache[i]->update.anchor;
session->size = cache[i]->update.size;
sprintf(dump->info, "%#x", session->anchor);
return (0);
}
cache[i]->init(argc, argv, session, dump->info);
sprintf(dump->info, "%#x", session->anchor);
return (0);
}
void command_entry(struct session_s *session, struct dump_s *dump)
{
char **argv;
int argc;
int ret;
if (history_update(&dump->history.list, dump->insert.cmd) == 0){
dump->history.offset = 0;
dump->history.deep += 1;
}
ret = strtotab(&argc, &argv, dump->insert.cmd);
memset(dump->insert.cmd, '\0', CMD_LENGHT_MAX);
if (ret != 0){
sprintf(dump->info, "error (%d)", ret);
return;
}
if (find_command(argc, argv, session, dump) != 0)
strcat(dump->info, "command error");
session->mode = (session->anchor == 0x00000000) ? UNUSED : NORMAL;
session->cursor = 0;
strtotab_quit(&argc, &argv);
}

20
src/commands/ram_jump.c Normal file
View File

@ -0,0 +1,20 @@
#include <commands.h>
#include <string.h>
void ram_jump(int argc, char **argv, struct session_s *session, char *info)
{
if (argc != 2){
strcpy(info, "arguments error");
return;
}
if (!strcmp(argv[1], "p0"))
session->anchor = 0x08100000;
if (!strcmp(argv[1], "p1"))
session->anchor = 0x88000000;
if (!strcmp(argv[1], "p2"))
session->anchor = 0xa8000000;
if (!strcmp(argv[1], "p2"))
session->anchor = 0xe6000000;
//FIXME: sh3 size is 0x40000;
session->size = 0x80000;
}

View File

@ -0,0 +1,24 @@
#include <commands.h>
#include <string.h>
static INLINE int check_address(char *str)
{
--str;
while ((*(++str) >= '0' && *str <= '9') || (*str >= 'a' && *str <= 'f'));
return ((*str != '\0') ? 1 : 0);
}
void syscall_jump(int argc, char **argv, struct session_s *session, char *info)
{
uint32_t *systab;
uint32_t id;
if (argc != 2 || check_address(argv[1]) != 0){
strcpy(info, "arguments error");
return;
}
id = atoi_base(argv[1], 16);
systab = (void*)(*(uint32_t *)0x8001007c);
session->anchor = systab[id];
session->size = 0xffffffff;
}

18
src/commands/vbr_jump.c Normal file
View File

@ -0,0 +1,18 @@
#include <commands.h>
#include <string.h>
void vbr_jump(int argc, char **argv, struct session_s *session, char *info)
{
if (argc != 2){
strcpy(info, "arguments error");
return;
}
__asm__ volatile ("stc vbr, %0" : "=r"(session->anchor));
if (!strcmp(argv[1], "fault"))
session->anchor += 0x100;
if (!strcmp(argv[1], "except"))
session->anchor += 0x400;
if (!strcmp(argv[1], "int"))
session->anchor += 0x600;
session->size = 2048;
}

69
src/display/intructions.c Normal file
View File

@ -0,0 +1,69 @@
#include <utils.h>
#include <syscalls.h>
#include <opcode.h>
#include <string.h>
//TODO:
// - move me !
// - attribute always inline ?
static INLINE int get_shift(uint16_t mask)
{
int i;
if (mask == 0x0000)
return (0);
i = -1;
while (++i < 16 && !(mask & (0x01 << i)));
return (i);
}
static void get_mnemonic(char *str, uint16_t bytes_code)
{
int shift[ARGUMENTS_MAX];
size_t i;
size_t j;
i = -1;
while (opcode[++i].name != NULL
&& (bytes_code & opcode[i].mask) != opcode[i].code);
if (opcode[i].name == NULL){
strcpy(str, "????");
return;
}
j = -1;
while (++j < ARGUMENTS_MAX)
shift[j] = get_shift(opcode[i].arg_mask[j]);
//TODO: update this.
sprintf(str, opcode[i].name,
(bytes_code & opcode[i].arg_mask[0]) >> shift[0],
(bytes_code & opcode[i].arg_mask[1]) >> shift[1],
(bytes_code & opcode[i].arg_mask[2]) >> shift[2]);
}
//TODO:
// - resize buffer.
// - handle multiple modes.
void display_instructions(const struct session_s *session)
{
char mnemonic[128];
uint16_t *area;
char buf[64];
size_t y;
if (session->mode == COMMAND){
restore_window(1);
return;
}
if (session->mode == UNUSED || session->anchor == 0x00000000){
print((SCREEN_WIDTH >> 1) - ((sizeof("Empty session") * FONT_WIDTH) >> 1),
(SCREEN_HEIGHT >> 1) - (FONT_HEIGHT >> 1), "Empty session");
return;
}
y = -1;
area = (void*)(session->anchor + session->cursor);
while (++y < LINE_OFFSET){
get_mnemonic(mnemonic, area[y]);
sprintf(buf, "%4x %4x %s", &(area[y]), area[y], mnemonic);
print(0, y * FONT_HEIGHT, buf);
}
}

26
src/display/metainfos.c Normal file
View File

@ -0,0 +1,26 @@
#include <utils.h>
#include <syscalls.h>
#include <string.h>
void display_metainfos(const struct dump_s *dump, const struct session_s *session)
{
static const char *mode_name[] = {"unused", "command", "normal", "free"};
static const char insert_name[] = {'l', 'L', 'n', 's'};
const void *tmp;
char buf[32];
// clear area
dclear_area(0, SCREEN_HEIGHT - FONT_HEIGHT - 2, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1);
dline_horizontal(SCREEN_HEIGHT - FONT_HEIGHT - 2, 0, SCREEN_WIDTH - 1);
// Display informations
sprintf(buf, "[%s][%d]", mode_name[session->mode], dump->current_session);
print(SCREEN_WIDTH - (strlen(buf) * FONT_WIDTH) - 1, SCREEN_HEIGHT - FONT_HEIGHT, buf);
if (session->mode == COMMAND)
sprintf(buf, "[%c]:%s#", insert_name[dump->insert.mode], dump->insert.cmd);
else {
tmp = (*dump->info == '\0') ? dump->insert.cmd : dump->info;
sprintf(buf, "[%c] %s", insert_name[dump->insert.mode], tmp);
}
print(0, SCREEN_HEIGHT - FONT_HEIGHT, buf);
}

48
src/history.c Normal file
View File

@ -0,0 +1,48 @@
#ifndef DEBUG
# include <history.h>
# include <syscalls.h>
#else
# include "history.h"
# include <stdlib.h>
#endif
#include <string.h>
#include <errno.h>
// TODO:write docs !
// *-*
// |A| -->
// *-*
int history_update(struct node **list, const char *data)
{
void *swap;
if (list == NULL)
return (EFAULT);
swap = *list;
*list = (struct node *)malloc(sizeof(struct node));
if (*list == NULL){
*list = swap;
return (ENOMEM);
}
strcpy((void*)(*list)->data, data);
(*list)->next = swap;
return (0);
}
const void *history_get(struct node *list, off_t offset)
{
if (list == NULL)
return (NULL);
if (offset == 0)
return (list->data);
return (history_get(list->next, offset - 1));
}
void history_quit(struct node **list)
{
if (list == NULL || *list == NULL)
return;
history_quit(&(*list)->next);
free(*list);
*list = NULL;
}

140
src/keys.c Normal file
View File

@ -0,0 +1,140 @@
#include <utils.h>
#include <syscalls.h>
#include <commands.h>
#include <string.h>
static int check_session(unsigned int key, struct dump_s *dump)
{
static const unsigned int keys_switch[SESSIONS_SLOT] = {
KEY_F1, KEY_F2, KEY_F3,
KEY_F4, KEY_F5, KEY_F6
};
size_t i;
i = -1;
while (++i < SESSIONS_SLOT && key != keys_switch[i]);
if (i < SESSIONS_SLOT){
dump->current_session = i;
return (0);
}
return (-1);
}
static int check_insert(unsigned int key, struct dump_s *dump, struct session_s *session)
{
if (!(key == KEY_OPTN || key == KEY_SHIFT || key == KEY_ALPHA))
return (-1);
if (dump->insert.mode == LETTER)
dump->insert.mode = NUMBER;
if (key == KEY_OPTN){
if (session->mode != COMMAND){
memset(dump->info, '\0', CMD_LENGHT_MAX);
session->mode = COMMAND;
save_window(1);
}
else
//TODO: restore FREE mode ?
session->mode = (session->anchor == 0x00000000) ? UNUSED : NORMAL;
}
if (key == KEY_SHIFT)
dump->insert.mode = (dump->insert.mode == SHIFT) ? NUMBER : SHIFT;
if (key == KEY_ALPHA){
if (dump->insert.mode == SHIFT){
dump->insert.mode = CAPS_LOCK;
return (0);
}
if (dump->insert.mode == CAPS_LOCK){
dump->insert.mode = NUMBER;
return (0);
}
dump->insert.mode = LETTER;
}
return (0);
}
//TODO: find better way to do the job (?)
static int check_cmd(unsigned int key, struct dump_s *dump, struct session_s *session)
{
static const unsigned int keys_alpha[] = {
KEY_A, KEY_B, KEY_C, KEY_D, KEY_E, KEY_F, KEY_G, KEY_H,
KEY_I, KEY_J, KEY_K, KEY_L, KEY_M, KEY_N, KEY_O, KEY_P,
KEY_Q, KEY_R, KEY_S, KEY_T, KEY_U, KEY_V, KEY_W, KEY_X,
KEY_Y, KEY_Z
};
static const unsigned int keys_number[] = {
KEY_0, KEY_1, KEY_2, KEY_3, KEY_4,
KEY_5, KEY_6, KEY_7, KEY_8, KEY_9
};
unsigned int *cache;
size_t size;
size_t end;
size_t i;
char buf;
if (session->mode != COMMAND)
return (-1);
i = -1;
size = strlen(dump->insert.cmd);
end = (dump->insert.mode == NUMBER) ? 10 : 26;
buf = (dump->insert.mode == NUMBER) ? '0' : 'a';
cache = (dump->insert.mode == NUMBER) ? (void *)keys_number : (void *)keys_alpha;
while (++i < end && key != cache[i]);
if (i >= end)
return (-1);
if (size < CMD_LENGHT_MAX){
buf += i;
strcat(dump->insert.cmd, &buf);
}
dump->history.offset = 0;
return (0);
}
static int check_arrow(unsigned int key, struct dump_s *dump, struct session_s *session)
{
if (key != KEY_UP && key != KEY_DOWN)
return (-1);
if (session->mode == COMMAND
&& ((key == KEY_UP && dump->history.offset < dump->history.deep)
|| (key == KEY_DOWN && dump->history.offset > 0))){
if (dump->history.offset == 0)
strcpy(dump->insert.backup, dump->insert.cmd);
dump->history.offset += (key == KEY_UP) ? 1 : -1;
if (dump->history.offset > 0)
strcpy(dump->insert.cmd,
history_get(dump->history.list, dump->history.offset - 1));
else
strcpy(dump->insert.cmd, dump->insert.backup);
}
if (session->mode != UNUSED && session->mode != COMMAND){
if (key == KEY_UP && session->cursor > 0)
session->cursor -= INSTRUCTION_SIZE;
if (key == KEY_DOWN && session->cursor < session->size - LINE_OFFSET)
session->cursor += INSTRUCTION_SIZE;
}
return (0);
}
void key_handling(struct dump_s *dump, struct session_s *session, unsigned int key)
{
size_t size;
if (check_session(key, dump) == 0
|| check_insert(key, dump, session) == 0
|| check_arrow(key, dump, session) == 0
|| check_cmd(key, dump, session) == 0
|| session->mode != COMMAND)
return;
if (key == KEY_DEL || key == KEY_INS){
size = strlen(dump->insert.cmd);
if (size > 0)
strncpy(dump->insert.cmd, dump->insert.cmd, size - 1);
}
if (key == KEY_SPACE)
strcat(dump->insert.cmd, " ");
if (key == KEY_QUOTE)
strcat(dump->insert.cmd, "\"");
if (key == KEY_ENTER){
dump->insert.mode = NUMBER;
command_entry(session, dump);
}
}

49
src/main.c Normal file
View File

@ -0,0 +1,49 @@
#include <utils.h>
#include <string.h>
#include <syscalls.h>
//
// dump_constructor()
// Initialize all information needed by the add-in: session,
// GetKey configuration, ...
//
static void dump_constructor(struct dump_s *dump)
{
size_t i;
i = -1;
memset(dump->info, '\0', CMD_LENGHT_MAX);
memset(dump->insert.cmd, '\0', CMD_LENGHT_MAX);
//TODO: Auto detect GetKey configuration !!
dump->insert.mode = NUMBER;
dump->history.list = NULL;
dump->history.offset = 0;
dump->history.deep = 0;
dump->current_session = 0;
while (++i < SESSIONS_SLOT){
dump->session[i].mode = UNUSED;
dump->session[i].anchor = 0x00000000;
}
}
//
// main()
// "user" entry, but we need initialize some information before
// starting the "main loop".
//
int main(void)
{
struct dump_s dump;
unsigned int key;
key = 0;
dump_constructor(&dump);
while (1){
dclear();
display_instructions(&dump.session[dump.current_session]);
display_metainfos(&dump, &dump.session[dump.current_session]);
getkey(&key);
key_handling(&dump, &dump.session[dump.current_session], key);
}
return (0);
}

26
src/string/atoi_base.c Normal file
View File

@ -0,0 +1,26 @@
#include <string.h>
static INLINE int check_base(char n, int base)
{
char max;
max = (base <= 10) ? '0' + base - 1 : ('a' + base - 11);
return ((max < n));
}
uint32_t atoi_base(char const *str, int base)
{
uint32_t result;
size_t start;
start = -1;
result = 0;
while (str[++start] != '\0' && check_base(str[start], base) == 0){
result *= base;
if (str[start] <= '9')
result += str[start] - '0';
else
result += (str[start] - 'a') + 10;
}
return (result);
}

9
src/string/memset.c Normal file
View File

@ -0,0 +1,9 @@
#include <utils.h>
//TODO: update me :(
__attribute__((weak)) void *memset(void *s, int c, size_t n)
{
while ((int)--n >= 0)
((uint8_t*)s)[n] = c;
return (s);
}

113
src/string/sprintf.c Normal file
View File

@ -0,0 +1,113 @@
#include <string.h>
static size_t strbase(char *dest, uint32_t nb, size_t size, int base)
{
uint32_t tmp;
if (base == 10){
if ((int32_t)nb < 0){
*(dest++) = '-';
nb = -nb;
}
}
if (size == 0){
tmp = nb;
while (tmp != 0){
tmp /= base;
size += 1;
}
if (size == 0)
size = 1;
}
tmp = size;
while ((int)(--size) >= 0){
*(dest + size) = ((nb % base) + '0') + (39 * ((nb % base) > 9));
nb /= base;
}
*(dest + tmp) = '\0';
return (tmp);
}
static size_t strndump(char *dest, char const *str, size_t size)
{
size_t i;
if (str == NULL || dest == NULL)
return (0);
i = -1;
while (++i < size && str[i] != '\0')
dest[i] = str[i];
dest[i] = '\0';
return (i);
}
__attribute__((weak)) void vsprintf(char *str, char const *format, va_list ap)
{
size_t size;
size_t len;
if (format == NULL)
return;
while (*format != '\0'){
if (*format != '%'){
*(str++) = *(format++);
continue;
}
/* get size informations */
size = 0;
len = -1;
format += 1;
while (format[++len] >= '0' && format[len] <= '9')
size = size * 10 + format[len] - '0';
if (format[len] == '%'){
*(str++) = '%';
format += 1;
continue;
}
if (format[len] == 'c'){
*(str++) = (char)va_arg(ap, int);
format += len + 1;
continue;
}
if (format[len] == 's'){
char const *tmp = va_arg(ap, char const *);
/* TODO: find better way to do the job */
str += strndump(str, tmp, (size == 0) ? 1024 : size);
format += len + 1;
continue;
}
if (format[len] == 'd'){
int nb = va_arg(ap, int);
str += strbase(str, nb, size, 10);
format += len + 1;
continue;
}
if (format[len] == 'x'){
int nb = va_arg(ap, int);
str += strbase(str, nb, size, 16);
format += len + 1;
continue;
}
if (format[len] == '#' && format[len + 1] == 'x'){
int nb = va_arg(ap, int);
*(str++) = '0';
*(str++) = 'x';
str += strbase(str, nb, 8, 16);
format += len + 2;
continue;
}
*(str++) = '%';
}
*str = '\0';
}
__attribute__((weak)) void sprintf(char *str, char const *format, ...)
{
va_list ap;
va_start(ap, format);
vsprintf(str, format, ap);
va_end(ap);
}

17
src/string/strcat.c Normal file
View File

@ -0,0 +1,17 @@
#include <string.h>
__attribute__((weak)) char *strcat(char *dest, char const *src)
{
size_t i;
size_t start;
if (src == NULL || dest == NULL)
return (0);
i = -1;
start = -1;
while (dest[++start] != '\0');
while (src[++i] != '\0')
dest[start + i] = src[i];
dest[i + start] = '\0';
return (dest);
}

12
src/string/strcmp.c Normal file
View File

@ -0,0 +1,12 @@
#include <string.h>
__attribute__((weak)) int strcmp(const char *s1, const char *s2)
{
if (s1 == NULL || s2 == NULL)
return (0);
while (*s1 != '\0' && *s2 != '\0' && *s1 == *s2){
s1 += 1;
s2 += 1;
}
return (*s1 - *s2);
}

27
src/string/strcpy.c Normal file
View File

@ -0,0 +1,27 @@
#include <string.h>
__attribute__((weak)) char *strcpy(char *dest, char const *src)
{
size_t i;
if (src == NULL || dest == NULL)
return (0);
i = -1;
while (src[++i] != '\0')
dest[i] = src[i];
dest[i] = '\0';
return (dest);
}
__attribute__((weak)) char *strncpy(char *dest, char const *str, size_t size)
{
size_t i;
if (str == NULL || dest == NULL)
return (0);
i = -1;
while (++i < size && str[i] != '\0')
dest[i] = str[i];
dest[i] = '\0';
return (dest);
}

12
src/string/strlen.c Normal file
View File

@ -0,0 +1,12 @@
#include <string.h>
__attribute__((weak)) size_t strlen(char const *str)
{
size_t i;
if (str == NULL)
return (0);
i = -1;
while (str[++i] != '\0');
return (i);
}

140
src/string/strtotab.c Normal file
View File

@ -0,0 +1,140 @@
#ifndef DEBUG
# include <commands.h>
# include <syscalls.h>
#else
# include "commands.h"
# include <stdlib.h>
# include <stdio.h>
#endif
#include <string.h>
#include <errno.h>
// Internal prototypes.
extern int strtotab(int *argc, char ***argv, char const *str);
extern void strtotab_quit(int *argc, char ***argv);
//
// parser_get_word()
// Get the word at the current cursor location.
//
static ssize_t parser_get_word(char ***tab, size_t *tab_pos,
char const *str, int *counter)
{
ssize_t i;
i = -1;
while (str[++i] != '\0' && str[i] != '\n' && str[i] != ' ' && str[i] != '\t');
if (*tab != NULL){
(*tab)[*tab_pos] = (char*)malloc(i + 1);
if ((*tab)[*tab_pos] == NULL)
return (-1);
memset((*tab)[*tab_pos], 0, i + 1);
strncpy((*tab)[(*tab_pos)++], str, i);
}
(*counter)++;
return (i);
}
//
// parser_get_inibitor()
// This function will get the content of an inibitor (and check if the
// inibitor charactere are alone or not).
//
static ssize_t parser_get_inibitor(char ***tab, size_t *tab_pos,
char const *str, int *counter)
{
ssize_t i;
i = 0;
while (str[++i] != '\0' && str[i] != '\"');
if (str[i] != '\"')
return (0);
if (*tab != NULL){
(*tab)[*tab_pos] = (char*)malloc(i + 1);
if ((*tab)[*tab_pos] == NULL)
return (-1);
memset((*tab)[*tab_pos], 0, i + 1);
strncpy((*tab)[(*tab_pos)++], str + 1, i - 1);
}
(*counter)++;
return (i + 1);
}
//
// parser_setup_arg()
// This function remove useless spaces, tabs and handle '\"' inibithor.
// Return the number of word(s) stored in `str`.
//
static int parser_entry(char ***tab, char const *str)
{
size_t tab_pos;
ssize_t size;
int counter;
str--;
counter = 0;
tab_pos = 0;
while (*(++str) != '\0' && *str != '\n'){
if (*str == '\"'){
size = parser_get_inibitor(tab, &tab_pos, str, &counter);
if (size < 0)
return (-1);
str += size;
}
if (*str != ' ' && *str != '\t'){
size = parser_get_word(tab, &tab_pos, str, &counter) - 1;
if (size < 0)
return (-1);
str += size;
}
}
return (counter);
}
//TODO:
// - write doc !
int strtotab(int *argc, char ***argv, char const *str)
{
int i;
// Check memory fault.
if (argc == NULL || argv == NULL || str == NULL)
return (EFAULT);
// Get the number of word.
*argv = NULL;
*argc = parser_entry(argv, str);
if (*argc <= 0)
return (EINVAL);
// Alloc tab.
*argv = (char **)malloc(sizeof(char *) * (*argc + 1));
if (*argv == NULL)
return (ENOMEM);
i = *argc;
while (--i >= 0)
(*argv)[i] = NULL;
// Get word.
if (parser_entry(argv, str) != *argc){
strtotab_quit(argc, argv);
return (ENOMEM);
}
(*argv)[*argc] = NULL;
return (0);
}
void strtotab_quit(int *argc, char ***argv)
{
if (argc == NULL || argv == NULL)
return;
if (*argv == NULL){
*argc = 0;
return;
}
while (--(*argc) >= 0)
free((*argv)[*argc]);
free(*argv);
*argv = NULL;
*argc = 0;
}

98
src/syscalls.s Normal file
View File

@ -0,0 +1,98 @@
.global _casio_GetKey
.global _casio_PrintMini
.global _casio_Bdisp_PutDisp_DD
.global _casio_Bdisp_AllClr_DDVRAM
.global _casio_Bdisp_DrawLine_VRAM
.global _casio_Bdisp_AreaClr_DDVRAM
.global _casio_RestoreDisp
.global _casio_SaveDisp
.global _casio_Malloc
.global _casio_Free
.type _casio_GetKey, @function
.type _casio_PrintMini, @function
.type _casio_Bdisp_PutDisp_DD, @function
.type _casio_Bdisp_AllClr_DDVRAM, @function
.type _casio_Bdisp_DrawLine_VRAM, @function
.type _casio_Bdisp_AreaClr_DDVRAM, @function
.type _casio_RestoreDisp, @function
.type _casio_SaveDisp, @function
.type _casio_Malloc, @function
.type _casio_Free, @function
.align 2
_casio_GetKey:
mov.l .syscall_tab, r1
mov.l .sys_getkey, r0
jmp @r1
nop
_casio_PrintMini:
mov.l .syscall_tab, r1
mov.l .sys_printMini, r0
jmp @r1
nop
_casio_Bdisp_AllClr_DDVRAM:
mov.l .syscall_tab, r1
mov.l .sys_clear, r0
jmp @r1
nop
_casio_Bdisp_PutDisp_DD:
mov.l .syscall_tab, r1
mov.l .sys_display, r0
jmp @r1
nop
_casio_Bdisp_DrawLine_VRAM:
mov.l .syscall_tab, r1
mov.l .sys_line, r0
jmp @r1
nop
_casio_Bdisp_AreaClr_DDVRAM:
mov.l .syscall_tab, r1
mov.l .sys_clear_area, r0
jmp @r1
nop
_casio_RestoreDisp:
mov.l .syscall_tab, r1
mov.l .sys_restore_disp, r0
jmp @r1
nop
_casio_SaveDisp:
mov.l .syscall_tab, r1
mov.l .sys_save_disp, r0
jmp @r1
nop
_casio_Malloc:
mov.l .syscall_tab, r1
mov.l .sys_malloc, r0
jmp @r1
nop
_casio_Free:
mov.l .syscall_tab, r1
mov.l .sys_free, r0
jmp @r1
nop
.align 4
.syscall_tab: .long 0x80010070
.sys_line: .long 0x00000030
.sys_clear: .long 0x00000143 /*Bdisp_AllClr_VRAM */
.sys_getkey: .long 0x0000090f
.sys_display: .long 0x00000028
.sys_printMini: .long 0x00000c4f
.sys_clear_area: .long 0x0000014c
.sys_restore_disp: .long 0x00000814
.sys_save_disp: .long 0x00000813
.sys_malloc: .long 0x00000acd
.sys_free: .long 0x00000acc
.end

31
tests/atoi_base_test.c Normal file
View File

@ -0,0 +1,31 @@
#include <criterion/criterion.h>
// Internal prototypes.
extern uint32_t atoi_base(char const *str, int base);
Test(atoi_base, base_10)
{
uint32_t result;
result = atoi_base("12345", 10);
cr_assert_eq(result, 12345, "returned: %d\n", result);
cr_assert_eq(atoi_base("50926", 10), 50926);
cr_assert_eq(atoi_base("999999", 10), 999999);
}
Test(atoi_base, base_16)
{
uint32_t result;
result = atoi_base("abcdef", 16);
cr_assert_eq(result, 0xabcdef, "returned: %#x\n", result);
cr_assert_eq(atoi_base("50926", 16), 0x50926);
cr_assert_eq(atoi_base("999999", 16), 0x999999);
}
Test(atoi_base, base_error)
{
cr_assert_eq(atoi_base("xxxxxx", 16), 0);
cr_assert_eq(atoi_base("50926x56", 16), 0x50926);
cr_assert_eq(atoi_base("o", 16), 0);
}

52
tests/history_test.c Normal file
View File

@ -0,0 +1,52 @@
#include <criterion/criterion.h>
#include "tests/internal.h"
#include "history.h"
#include <errno.h>
//TODO: write doc.
Test(history, add)
{
struct node *list;
list = NULL;
cr_assert_eq(history_update(&list, "ls -l"), 0);
cr_assert_eq(history_update(&list, "cat -e"), 0);
cr_assert_eq(history_update(NULL, "cat -e"), EFAULT);
// malloc fails.
malloc_hook_update(FAIL_NEXT);
cr_assert_eq(history_update(&list, "cat -e"), ENOMEM);
// Check info.
cr_assert_str_eq(list->data, "cat -e");
cr_assert_str_eq(list->next->data, "ls -l");
cr_assert_null(list->next->next);
}
Test(history, get)
{
struct node *list;
list = NULL;
history_update(&list, "ls -l");
history_update(&list, "cat -e");
cr_assert_str_eq(history_get(list, 1), "ls -l");
cr_assert_str_eq(history_get(list, 0), "cat -e");
cr_assert_null(history_get(list, 4));
}
Test(history, quit)
{
struct node *list;
list = NULL;
history_quit(&list);
history_update(&list, "ls -l");
history_update(&list, "cat -e");
history_update(&list, "test");
history_update(&list, "yes");
history_quit(&list);
history_quit(NULL);
cr_assert_null(list);
}

24
tests/internal.h Normal file
View File

@ -0,0 +1,24 @@
#ifndef __INTERNAL_H__
# define __INTERNAL_H__
#include <stddef.h>
#include <stdint.h>
//
// status_t - all status available for hook.
// * FAIL_NONE : force malloc to work normaly.
// * FAIL_NEXT : force the next call of malloc to return NULL.
// * FAIL_ALWAYS : force all malloc to return NULL.
//
typedef enum status_e
{
FAIL_NONE,
FAIL_NEXT,
FAIL_ALWAYS,
FAIL_NEXT_DYN
} status_t;
/* malloc_hook_update - udpate the behavior of the malloc hook */
void malloc_hook_update(status_t status, ...);
#endif /*__INTERNAL_H__*/

90
tests/malloc_hook.c Normal file
View File

@ -0,0 +1,90 @@
#include "tests/internal.h"
#include <malloc.h>
#include <stdarg.h>
// Internal prototypes / static symbols.
static void my_malloc_init_hook(void);
static void *my_malloc_hook(size_t size, const void *caller);
static void *old_malloc_hook;
static int hook_dyn_fail;
static int hook_status;
//
// my_malloc_hook()
// This function will replace the current malloc hook by our own
// hook (which can return NULL if we want, it allows us to check
// the behavior of our code).
//
// NOTE:
// "man __malloc_hook" indicate to use "__malloc_initialize_hook"
// which will execute the initialization routine. But from glibc 2.24
// onwards, this variable has been removed from the API.
// So, this is why we use "constructor" attribute to call our routine
// at the beginning of the test.
//
__attribute__((constructor))
static void my_malloc_init_hook(void)
{
old_malloc_hook = __malloc_hook;
__malloc_hook = my_malloc_hook;
hook_status = FAIL_NONE;
}
//
// my_malloc_hook()
// For some tests we need to simulate (properly) a malloc fail; to do this
// we use a malloc hook and add static variables to force him to return
// NULL address.
//
// NOTE:
// All hooks of the glibc will be removed because of their poor behavior
// in multi threaded environment.
// But recently we have seen that the malloc() function is defined by the
// weak symbol, so it is probably possible to override malloc() and do
// the same job.
//
static void *my_malloc_hook(size_t size, const void *caller)
{
void *result;
if (hook_status != FAIL_NONE && hook_status != FAIL_NEXT_DYN){
if (hook_status == FAIL_NEXT)
hook_status = FAIL_NONE;
return (NULL);
}
if (hook_status == FAIL_NEXT_DYN){
hook_dyn_fail -= 1;
if (hook_dyn_fail <= 0){
hook_status = FAIL_NONE;
return (NULL);
}
}
__malloc_hook = old_malloc_hook;
result = malloc(size);
(void)caller;
//printf("caller: %p - area: %p\n", caller, result);
old_malloc_hook = __malloc_hook;
__malloc_hook = my_malloc_hook;
return (result);
}
//
// malloc_hook_udpate()
// This function is the only way to interact with the hook; it will
// define the behavior of malloc:
// * FAIL_NEXT : force the next call of malloc to return NULL.
// * FAIL_ALWAYS : force all malloc return NULL.
// * NORMAL : force malloc to work normally.
//
void malloc_hook_update(status_t status, ...)
{
va_list ap;
hook_dyn_fail = 0;
if (status == FAIL_NEXT_DYN){
va_start(ap, status);
hook_dyn_fail = va_arg(ap, int);
va_end(ap);
}
hook_status = status;
}

108
tests/strtab_test.c Normal file
View File

@ -0,0 +1,108 @@
#include <criterion/criterion.h>
#include "tests/internal.h"
#include <errno.h>
// Internal prototypes.
extern int strtotab(int *argc, char ***argv, char const *str);
extern void strtotab_quit(int *argc, char ***argv);
Test(strtotab, quote)
{
char **argv;
int argc;
int ret;
ret = strtotab(&argc, &argv, "hey? \"What's \nup?\" yo!\"\n");
cr_expect_eq(ret, 0);
cr_expect_eq(argc, 3);
cr_assert_str_eq(argv[0], "hey?");
cr_assert_str_eq(argv[1], "What's \nup?");
cr_assert_str_eq(argv[2], "yo!\"");
}
Test(strtotab, noword)
{
char **argv;
int argc;
int ret;
ret = strtotab(&argc, &argv, "");
cr_expect_eq(ret, EINVAL);
cr_expect_eq(argc, 0);
cr_assert_null(argv);
}
Test(strtotab, entry_error)
{
char **argv;
int argc;
int ret;
ret = strtotab(NULL, &argv, "aaaaaaaaa aa");
cr_expect_eq(ret, EFAULT);
ret = strtotab(&argc, NULL, "aaaaaaaaa aa");
cr_expect_eq(ret, EFAULT);
ret = strtotab(&argc, &argv, NULL);
cr_expect_eq(ret, EFAULT);
}
Test(strtotab, spaces_tabs)
{
char **argv;
int argc;
int ret;
ret = strtotab(&argc, &argv, "hey? What's\t\t \t up?");
cr_expect_eq(ret, 0);
cr_expect_eq(argc, 3);
cr_assert_str_eq(argv[0], "hey?");
cr_assert_str_eq(argv[1], "What's");
cr_assert_str_eq(argv[2], "up?");
}
Test(strtotab, normal)
{
char **argv;
int argc;
int ret;
ret = strtotab(&argc, &argv, "hey? What's up?\n");
cr_expect_eq(ret, 0);
cr_assert_eq(argc, 3);
cr_assert_str_eq(argv[0], "hey?");
cr_assert_str_eq(argv[1], "What's");
cr_assert_str_eq(argv[2], "up?");
}
Test(strtotab, alloc_fails)
{
char **argv;
int argc;
int ret;
malloc_hook_update(FAIL_NEXT);
ret = strtotab(&argc, &argv, "hey? \"What's up?");
cr_assert_eq(ret, ENOMEM);
malloc_hook_update(FAIL_NEXT_DYN, 2);
ret = strtotab(&argc, &argv, "hey? \"What's up?");
cr_assert_eq(ret, ENOMEM);
malloc_hook_update(FAIL_NEXT_DYN, 2);
ret = strtotab(&argc, &argv, "\"What's\" up?");
cr_assert_eq(ret, ENOMEM);
}
Test(strtotab, quit)
{
char **argv;
int argc;
strtotab(&argc, &argv, "hey? What's up?");
strtotab_quit(&argc, &argv);
cr_assert_eq(argc, 0);
cr_assert_null(argv);
strtotab_quit(NULL, &argv);
strtotab_quit(&argc, NULL);
argv = NULL;
strtotab_quit(&argc, &argv);
}