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:
parent
441e57ee53
commit
7a0e037705
|
@ -52,3 +52,6 @@ Module.symvers
|
|||
Mkfile.old
|
||||
dkms.conf
|
||||
|
||||
# Other
|
||||
*.txt
|
||||
build/
|
||||
|
|
|
@ -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
|
|
@ -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.*)
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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__*/
|
|
@ -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__ */
|
|
@ -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__*/
|
File diff suppressed because it is too large
Load Diff
|
@ -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__*/
|
|
@ -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__*/
|
|
@ -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__*/
|
|
@ -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__*/
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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__*/
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
Loading…
Reference in New Issue