소스 검색

Implements labels declaration & references

For the moment labels are only subsituted with relative notation
". +/- OFFSET"
Yann Weber 1 년 전
부모
커밋
be9be061c9
17개의 변경된 파일478개의 추가작업 그리고 143개의 파일을 삭제
  1. 26
    0
      README.md
  2. 2
    2
      src/Makefile.am
  3. 8
    0
      src/asm_env.c
  4. 4
    0
      src/asm_env.h
  5. 50
    2
      src/asmsh.h
  6. 1
    1
      src/history.c
  7. 2
    0
      src/history.h
  8. 113
    2
      src/shell.c
  9. 10
    0
      src/shell.h
  10. 5
    120
      src/shell_cmd_breakpoint.c
  11. 76
    0
      src/shell_cmds.c
  12. 10
    3
      src/shell_cmds.h
  13. 106
    0
      src/shell_cmds_lib.c
  14. 43
    0
      src/shell_cmds_lib.h
  15. 6
    5
      src/shell_sym.c
  16. 9
    1
      src/shell_sym.h
  17. 7
    7
      tests/tests_shell_sym.c

+ 26
- 0
README.md 파일 보기

138
 asmsh@0x7f3020bec00b > .regs %rbx
138
 asmsh@0x7f3020bec00b > .regs %rbx
139
 rbx: 0000000000000042
139
 rbx: 0000000000000042
140
 ```
140
 ```
141
+
142
+**Make a loop with a label**
143
+
144
+```text
145
+asmsh@0x7f0fadb73000 > mov $27, %rcx
146
+asmsh@0x7f0fadb73005 > .label print
147
+INFO: Label '@print' 00007f0fadb73005 added
148
+asmsh@0x7f0fadb73005 > push %rcx
149
+asmsh@0x7f0fadb73006 > mov $27,%rbx
150
+asmsh@0x7f0fadb7300b > sub %rcx, %rbx
151
+asmsh@0x7f0fadb7300e > add $0x0a40, %rbx
152
+asmsh@0x7f0fadb73015 > push %rbx
153
+asmsh@0x7f0fadb73016 > mov $1, %rax
154
+asmsh@0x7f0fadb7301b > mov %rax, %rdi
155
+asmsh@0x7f0fadb7301e > mov %rsp, %rsi
156
+asmsh@0x7f0fadb73021 > mov $2, %rdx
157
+asmsh@0x7f0fadb73026 > syscall
158
+@
159
+asmsh@0x7f0fadb73028 > pop %rbx
160
+asmsh@0x7f0fadb73029 > pop %rcx
161
+asmsh@0x7f0fadb7302a > .breakpoint after loop @print
162
+INFO: Set breakpoint @ 00007F0FADB7302C
163
+asmsh@0x7f0fadb73005 > .run
164
+[...]
165
+```
166
+
141
 ## Tests & docs
167
 ## Tests & docs
142
 
168
 
143
 **Run tests and coverage**
169
 **Run tests and coverage**

+ 2
- 2
src/Makefile.am 파일 보기

5
 
5
 
6
 libcheck_asmsh_a_SOURCES = mmap_parse.c asm_env.c breakpoints.c compile.c logger.c \
6
 libcheck_asmsh_a_SOURCES = mmap_parse.c asm_env.c breakpoints.c compile.c logger.c \
7
 			   completion.c history.c \
7
 			   completion.c history.c \
8
-			   shell.c shell_cmds.c shell_sym.c \
8
+			   shell.c shell_cmds.c shell_sym.c shell_cmds_lib.c \
9
 			   shell_cmd_breakpoint.c
9
 			   shell_cmd_breakpoint.c
10
 
10
 
11
 noinst_HEADERS = asmsh.h mmap_parse.h asm_env.h breakpoints.h compile.h logger.h \
11
 noinst_HEADERS = asmsh.h mmap_parse.h asm_env.h breakpoints.h compile.h logger.h \
12
 		completion.h history.h \
12
 		completion.h history.h \
13
-		shell.h shell_cmds.h shell_sym.h syscalls.h
13
+		shell.h shell_cmds.h shell_sym.h shell_cmds_lib.h syscalls.h
14
 
14
 
15
 
15
 
16
 asmsh_SOURCES = asmsh.c $(libcheck_asmsh_a_SOURCES)
16
 asmsh_SOURCES = asmsh.c $(libcheck_asmsh_a_SOURCES)

+ 8
- 0
src/asm_env.c 파일 보기

37
 		errno = err;
37
 		errno = err;
38
 		return NULL;
38
 		return NULL;
39
 	}
39
 	}
40
+	/** @todo better error checks & clean */
40
 	child_mmap_init(&(res->mmap));
41
 	child_mmap_init(&(res->mmap));
41
 
42
 
42
 	asmsh_brk_init(&res->brks);
43
 	asmsh_brk_init(&res->brks);
43
 
44
 
45
+	if(asmsh_symtable_init(&res->labels) < 0)
46
+	{
47
+		asmsh_log_perror("Unable to initialize labels symtable");
48
+		return NULL;
49
+	}
50
+
44
 	res->childpath = NULL;
51
 	res->childpath = NULL;
45
 	if(childpath && (res->childpath = strdup(childpath)) == NULL)
52
 	if(childpath && (res->childpath = strdup(childpath)) == NULL)
46
 	{
53
 	{
89
 	}
96
 	}
90
 	kill(asmenv->pid, SIGKILL);
97
 	kill(asmenv->pid, SIGKILL);
91
 	asmsh_brk_free(&asmenv->brks);
98
 	asmsh_brk_free(&asmenv->brks);
99
+	asmsh_symtable_clean(&asmenv->labels);
92
 	free(asmenv->childpath);
100
 	free(asmenv->childpath);
93
 	free(asmenv);
101
 	free(asmenv);
94
 }
102
 }

+ 4
- 0
src/asm_env.h 파일 보기

33
 #define ASMSH_CHILD_TEXT_MAP_SZ 0x1000 // defined in child.s
33
 #define ASMSH_CHILD_TEXT_MAP_SZ 0x1000 // defined in child.s
34
 
34
 
35
 typedef struct asmsh_env_s asmsh_env_t;
35
 typedef struct asmsh_env_s asmsh_env_t;
36
+#include "shell_sym.h"
36
 
37
 
37
 struct asmsh_env_s
38
 struct asmsh_env_s
38
 {
39
 {
60
 	/** List of breakpoints addresses in child's memory */
61
 	/** List of breakpoints addresses in child's memory */
61
 	asmsh_brk_t brks;
62
 	asmsh_brk_t brks;
62
 
63
 
64
+	/** List of labels addresses in child's memory */
65
+	asmsh_symtable_t labels;
66
+
63
 	/** @todo check & delete useless properties */
67
 	/** @todo check & delete useless properties */
64
 	/** Pointer on the next addr where we should write some
68
 	/** Pointer on the next addr where we should write some
65
 	 *  compiled bytecode */
69
 	 *  compiled bytecode */

+ 50
- 2
src/asmsh.h 파일 보기

63
 loop . - 4
63
 loop . - 4
64
 </pre>
64
 </pre>
65
 
65
 
66
+@par Labels
67
+Labels can be defined to ease relative jumps using the ".label" command.
68
+Labels are used using "@NAME" notation, they are substituted with
69
+". SIGN OFFSET" with SIGN and OFFSET calculated from RIP value.
70
+
71
+@par Example
72
+The instruction "loop @lbl" could be transformed in "loop . - 8"
73
+
66
 @section shell_cmds COMMANDS
74
 @section shell_cmds COMMANDS
67
 
75
 
76
+@par .breakpoint [CMD] [OPTS...]
77
+Handle breakpoint with different subcommands :
78
+- add (implicit) add a breakpoint at given address (or RIP value if no address given)
79
+- del remove a breakpoint at given address (or RIP)
80
+- list list all breakpoints
68
 @par .bytecode
81
 @par .bytecode
69
 Compile an instruction and display it's bytecode
82
 Compile an instruction and display it's bytecode
70
 @par .flags
83
 @par .flags
71
 Display the CPU flags
84
 Display the CPU flags
72
 @par .help [COMMAND]
85
 @par .help [COMMAND]
73
 Display the builtin help or the help of the command gioven as argument
86
 Display the builtin help or the help of the command gioven as argument
87
+@par .label [NAME] [ADDR]
88
+Handle labels :
89
+- if no name given all labels are displayed.
90
+- if a name is given without address, a label is set at RIP value
91
+- if address is 0, the label is deleted
74
 @par .maps
92
 @par .maps
75
 Display process memory maps
93
 Display process memory maps
76
 @par .quit
94
 @par .quit
82
 @par .reset
100
 @par .reset
83
 Reset the shell (spawn a new process)
101
 Reset the shell (spawn a new process)
84
 
102
 
103
+@section Files
104
+
105
+@par ~/.local/share/asmsh/asmsh.history
106
+The command history file
107
+
85
 @section EXAMPLES
108
 @section EXAMPLES
86
 
109
 
87
 @subsection example_exit Exit with a specific status
110
 @subsection example_exit Exit with a specific status
125
 rbx: 0000000000000042
148
 rbx: 0000000000000042
126
 </pre>
149
 </pre>
127
 
150
 
151
+@subsection label_loop Make a loop using a label
152
+
153
+<pre>
154
+asmsh@0x7f0fadb73000 > mov $27, \%rcx
155
+asmsh@0x7f0fadb73005 > .label print
156
+INFO: Label '@print' 00007f0fadb73005 added
157
+asmsh@0x7f0fadb73005 > push \%rcx
158
+asmsh@0x7f0fadb73006 > mov $27,\%rbx
159
+asmsh@0x7f0fadb7300b > sub \%rcx, \%rbx
160
+asmsh@0x7f0fadb7300e > add $0x0a40, \%rbx
161
+asmsh@0x7f0fadb73015 > push \%rbx
162
+asmsh@0x7f0fadb73016 > mov $1, \%rax
163
+asmsh@0x7f0fadb7301b > mov \%rax, \%rdi
164
+asmsh@0x7f0fadb7301e > mov \%rsp, \%rsi
165
+asmsh@0x7f0fadb73021 > mov $2, \%rdx
166
+asmsh@0x7f0fadb73026 > syscall
167
+@
168
+asmsh@0x7f0fadb73028 > pop \%rbx
169
+asmsh@0x7f0fadb73029 > pop \%rcx
170
+asmsh@0x7f0fadb7302a > .breakpoint after loop @print
171
+INFO: Set breakpoint @ 00007F0FADB7302C
172
+asmsh@0x7f0fadb73005 > .run
173
+[...]
174
+</pre>
175
+
128
 @section TODO TODOLIST
176
 @section TODO TODOLIST
129
 
177
 
130
 @todo Implement command for memory read/dump
178
 @todo Implement command for memory read/dump
131
-@todo Implement symbols for jumps
132
-@todo Add support for label declarations & references
133
 @todo Implement write without exec
179
 @todo Implement write without exec
134
 @todo Implement function declaration
180
 @todo Implement function declaration
135
 @todo Add switch between intel's & AT&T's syntaxes.
181
 @todo Add switch between intel's & AT&T's syntaxes.
136
 @todo Implement a command to run until syscall only (and another for run until
182
 @todo Implement a command to run until syscall only (and another for run until
137
 		breakpoint or syscall ?)
183
 		breakpoint or syscall ?)
138
 @todo Rationalise commands argument parsing (at the moment .breakpoints allready uses special stuff :/)
184
 @todo Rationalise commands argument parsing (at the moment .breakpoints allready uses special stuff :/)
185
+@todo Enhance support for labels & far/abs jump
186
+@todo Implement a script run mode without the prompt & without readline
139
 
187
 
140
 @section AUTHOR
188
 @section AUTHOR
141
 Written by Yann Weber &lt;yann.weber@members.fsf.org&gt;
189
 Written by Yann Weber &lt;yann.weber@members.fsf.org&gt;

+ 1
- 1
src/history.c 파일 보기

2
 
2
 
3
 char * history_filename_init(const char *homedir)
3
 char * history_filename_init(const char *homedir)
4
 {
4
 {
5
-	const char fmt[] = "%s/.local/share/asmsh";
5
+	const char fmt[] = ASMSH_HISTORY_PATH_FMT;
6
 	int sz;
6
 	int sz;
7
 	const char *home = homedir?homedir:getenv("HOME");
7
 	const char *home = homedir?homedir:getenv("HOME");
8
 	if(!home)
8
 	if(!home)

+ 2
- 0
src/history.h 파일 보기

25
 #include <sys/types.h>
25
 #include <sys/types.h>
26
 #include <sys/stat.h>
26
 #include <sys/stat.h>
27
 
27
 
28
+#define ASMSH_HISTORY_PATH_FMT "%s/.local/share/asmsh"
29
+
28
 static const char ASMSH_HISTORY_FILE[] = "asmsh.history";
30
 static const char ASMSH_HISTORY_FILE[] = "asmsh.history";
29
 
31
 
30
 typedef void(add_history_f)(const char*);
32
 typedef void(add_history_f)(const char*);

+ 113
- 2
src/shell.c 파일 보기

80
 static int _compile_step(asmsh_t *sh, const char *cmd);
80
 static int _compile_step(asmsh_t *sh, const char *cmd);
81
 /** Attempt to handle given shell internal command (starting with  '.') */
81
 /** Attempt to handle given shell internal command (starting with  '.') */
82
 static int _handle_command(asmsh_t *sh, const char *cmd);
82
 static int _handle_command(asmsh_t *sh, const char *cmd);
83
-int asmsh_exec(asmsh_t *sh, const char *cmd)
83
+int asmsh_exec(asmsh_t *sh, const char *_cmd)
84
 {
84
 {
85
-	if(!cmd)
85
+	if(!_cmd)
86
 	{
86
 	{
87
 		errno=EINVAL;
87
 		errno=EINVAL;
88
 		return -1;
88
 		return -1;
89
 	}
89
 	}
90
 
90
 
91
+	char *cmd;
92
+	char prealloc_cmd[4096];
93
+	char *m_cmd = NULL;
94
+	cmd = prealloc_cmd;
95
+
96
+	size_t need_sz = asmsh_parse_labels(sh,
97
+			ASMSH_LABEL_SYM, _cmd, prealloc_cmd, 4096);
98
+	if(need_sz == 0)
99
+	{
100
+		return -1;
101
+	}
102
+
103
+	if(need_sz > 4096)
104
+	{
105
+		if(!(m_cmd = malloc(need_sz)))
106
+		{
107
+			asmsh_log_perror("Unable to allocate memory for parsed commandline");
108
+			return -1;
109
+		}
110
+		asmsh_parse_labels(sh, ASMSH_LABEL_SYM, _cmd, m_cmd, need_sz);
111
+		cmd = m_cmd;
112
+	}
113
+
91
 	int ret;
114
 	int ret;
92
 	//lstrip whitespace
115
 	//lstrip whitespace
93
 	for(; *cmd && (*cmd == ' ' || *cmd == '\t'); cmd++);
116
 	for(; *cmd && (*cmd == ' ' || *cmd == '\t'); cmd++);
102
 			ret = _compile_step(sh, cmd);
125
 			ret = _compile_step(sh, cmd);
103
 			break;
126
 			break;
104
 	}
127
 	}
128
+	if(m_cmd) { free(m_cmd); }
105
 	if(!ret)
129
 	if(!ret)
106
 	{
130
 	{
107
 		asmsh_env_update_regs(sh->env);
131
 		asmsh_env_update_regs(sh->env);
187
 	asmsh_cmd_args_free(args);
211
 	asmsh_cmd_args_free(args);
188
 	return ret;
212
 	return ret;
189
 }
213
 }
214
+
215
+
216
+size_t asmsh_parse_labels(asmsh_t *sh, char preffix, const char *cmd,
217
+		char *buf, size_t buf_sz)
218
+{
219
+	asmsh_symtable_t *table = &sh->env->labels;
220
+	const char *cmdptr, *prevptr;
221
+	size_t res, prev_sz;
222
+	
223
+	cmdptr = prevptr = cmd;
224
+
225
+	res = 0;
226
+	prev_sz = 0;
227
+	while(*cmdptr)
228
+	{
229
+		if(*cmdptr != preffix)
230
+		{
231
+			cmdptr++;
232
+			prev_sz++;
233
+			continue;
234
+		}
235
+		if(res + prev_sz < buf_sz)
236
+		{
237
+			// enough buffer to write
238
+			memcpy(buf+res, prevptr, prev_sz);
239
+		}
240
+		res += prev_sz;
241
+		cmdptr++;
242
+		prevptr = cmdptr;
243
+		prev_sz = 0;
244
+		// cmdptr is on start of the symbol, looking for end
245
+		while(*cmdptr && ( (*cmdptr >= 'a' && *cmdptr <= 'z') ||\
246
+					(*cmdptr >= 'A' && *cmdptr <= 'Z') ||\
247
+					(*cmdptr >= '0' && *cmdptr <= '9') ||\
248
+					*cmdptr == '-' || *cmdptr == '_'))
249
+		{
250
+			cmdptr++;
251
+		}
252
+		size_t symlen=cmdptr-prevptr;
253
+		char symname[symlen+1];
254
+		memcpy(symname, prevptr, symlen);
255
+		symname[symlen] = '\0';
256
+
257
+		const asmsh_sym_t *sym = asmsh_symtable_get(table, symname);
258
+		if(!sym)
259
+		{
260
+			asmsh_log_error("Symbol '%c%s' not found",
261
+					preffix, symname);
262
+			return 0;
263
+		}
264
+
265
+		const char fmt_addr[] = ". %c 0x%lx";
266
+		char sign = sym->addr > sh->env->regs.rip ? '+': '-';
267
+		size_t offset = sym->addr > sh->env->regs.rip ?  \
268
+				sym->addr - sh->env->regs.rip:\
269
+				sh->env->regs.rip - sym->addr;
270
+		int sz_print = snprintf(NULL, 0, fmt_addr, sign, offset);
271
+		if(res + sz_print + 1 < buf_sz)
272
+		{
273
+			res += snprintf(&buf[res], sz_print+1, fmt_addr, sign, offset);
274
+		}
275
+		else
276
+		{
277
+			res += sz_print;
278
+		}
279
+		prevptr=cmdptr;
280
+		prev_sz=0;
281
+	}
282
+	if(res + prev_sz < buf_sz)
283
+	{
284
+		// enough buffer to writea
285
+		memcpy(buf+res, prevptr, prev_sz);
286
+	}
287
+	res += prev_sz;
288
+	if(res < buf_sz)
289
+	{
290
+		buf[res] = '\0';
291
+		res++;
292
+	}
293
+	else if(buf_sz)
294
+	{
295
+		// ensure \0 is at end of string
296
+		buf[buf_sz-1] = '\0';
297
+	}
298
+	return res;
299
+}
300
+

+ 10
- 0
src/shell.h 파일 보기

44
 /** @return <0 on error 0 on ok 1 on exit */
44
 /** @return <0 on error 0 on ok 1 on exit */
45
 int asmsh_exec(asmsh_t *sh, const char *cmd);
45
 int asmsh_exec(asmsh_t *sh, const char *cmd);
46
 
46
 
47
+/** Parse all symbols found in given command
48
+ * @param asmsh_t* The shell
49
+ * @param char The prefix character before a symbol name
50
+ * @param const char* The string we want to parse
51
+ * @param char* A pointer on a buffer large enough to store the parsed string
52
+ * @param size_t The buffer size
53
+ * @return 0 on error else return the needed buffer size
54
+ */
55
+size_t asmsh_parse_labels(asmsh_t *sh, char preffix, const char *cmd,
56
+		char *buf, size_t buf_sz);
47
 
57
 
48
 #include "shell_cmds.h" // declares the static commands list
58
 #include "shell_cmds.h" // declares the static commands list
49
 
59
 

+ 5
- 120
src/shell_cmd_breakpoint.c 파일 보기

48
  */
48
  */
49
 static int brk_ls(asmsh_t *sh, asmsh_cmd_args_t *args, int expr_first);
49
 static int brk_ls(asmsh_t *sh, asmsh_cmd_args_t *args, int expr_first);
50
 
50
 
51
-/** Parse a breakpoint address expression
52
- *
53
- * An expression must be of the form A [OP B] with A and B
54
- * an integer or '.' for current RIP value and OP one of + or -
55
- *
56
- * @param asmsh_cmd_args_t* The breakpoint command argument list
57
- * @param int The first argument of the address expression
58
- * @param const unsigned long RIP value
59
- * @param unsigned long* A pointer on the result address
60
- *
61
- * @returns -1 on error and 0 if ok
62
- */
63
-static int parse_addr_expr(asmsh_cmd_args_t *args, int first,
64
-		const unsigned long rip,  unsigned long *addr);
65
-
66
-/** Utility function for @ref parse_addr_expr() that parse an expression value.
67
- *
68
- * An expression can be . for rip value or an unsigned long, possibly in hex, etc
69
- * @param const char* The value
70
- * @param unsigned long The value of RIP
71
- * @param unsigned long* A pointer on the result
72
- * @return -1 on error else 0
73
- */
74
-static int addr_expr_val(const char *val, unsigned long rip, unsigned long *res);
75
-
76
 /** Add a breakpoint and display a message about it
51
 /** Add a breakpoint and display a message about it
77
  * @param asmsh_t The shell
52
  * @param asmsh_t The shell
78
  * @param unsigned long The breakpoint address
53
  * @param unsigned long The breakpoint address
81
 static int brk_add_or_err(asmsh_t *sh, unsigned long addr);
56
 static int brk_add_or_err(asmsh_t *sh, unsigned long addr);
82
 
57
 
83
 
58
 
84
-void log_expr_usage()
85
-{
86
-	asmsh_log_info("Expected an address expression of the form A + B or A - B with A and B an integer or '.' (for current RIP value)");
87
-}
88
-
89
 void log_brk_usage()
59
 void log_brk_usage()
90
 {
60
 {
91
 	asmsh_log_info("Available commands are :");
61
 	asmsh_log_info("Available commands are :");
97
 	asmsh_log_info("\t\tAdd a new breakpoint after an instruction");
67
 	asmsh_log_info("\t\tAdd a new breakpoint after an instruction");
98
 	asmsh_log_info("\tlist|ls|l");
68
 	asmsh_log_info("\tlist|ls|l");
99
 	asmsh_log_info("\t\tList existing breakpoints");
69
 	asmsh_log_info("\t\tList existing breakpoints");
100
-	log_expr_usage();
70
+	asmsh_log_addr_expr_usage();
101
 }
71
 }
102
 
72
 
103
 
73
 
110
 	{
80
 	{
111
 		if((ret = brk_add(sh, args, 0)) < 0)
81
 		if((ret = brk_add(sh, args, 0)) < 0)
112
 		{
82
 		{
113
-			log_expr_usage();
83
+			asmsh_log_addr_expr_usage();
114
 		}
84
 		}
115
 		return ret;
85
 		return ret;
116
 	}
86
 	}
125
 	{
95
 	{
126
 		if((ret = brk_add(sh, args, 1)) < 0)
96
 		if((ret = brk_add(sh, args, 1)) < 0)
127
 		{
97
 		{
128
-			log_expr_usage();
98
+			asmsh_log_addr_expr_usage();
129
 		}
99
 		}
130
 		return ret;
100
 		return ret;
131
 	}
101
 	}
191
 
161
 
192
 	unsigned long addr;
162
 	unsigned long addr;
193
 
163
 
194
-	if(parse_addr_expr(args, expr_first, rip, &addr) < 0)
164
+	if(asmsh_cmd_parse_addr_expr(args, expr_first, rip, &addr) < 0)
195
 	{
165
 	{
196
 		return -1;
166
 		return -1;
197
 	}
167
 	}
224
 
194
 
225
 	unsigned long addr;
195
 	unsigned long addr;
226
 
196
 
227
-	if(parse_addr_expr(args, expr_first, rip, &addr) < 0)
197
+	if(asmsh_cmd_parse_addr_expr(args, expr_first, rip, &addr) < 0)
228
 	{
198
 	{
229
 		return -1;
199
 		return -1;
230
 	}
200
 	}
258
 	return 0;
228
 	return 0;
259
 }
229
 }
260
 
230
 
261
-static int addr_expr_val(const char *val, unsigned long rip, unsigned long *res)
262
-{
263
-	if(strcmp(".", val) == 0)
264
-	{
265
-		*res = rip;
266
-		return 0;
267
-	}
268
-
269
-	char *endptr;
270
-	errno = 0;
271
-	*res = strtoul(val, &endptr, 0);
272
-	if(errno != 0)
273
-	{
274
-		return -1;
275
-	}
276
-	else if(*endptr != '\0')
277
-	{
278
-		errno = EINVAL;
279
-		return -1;
280
-	}
281
-	return 0;
282
-}
283
-
284
-static int parse_addr_expr(asmsh_cmd_args_t *args, int first,
285
-		const unsigned long rip, unsigned long *addr)
286
-{
287
-	char * const * argv = args->args + first;
288
-	const int argc = args->argc - first;
289
-
290
-	unsigned long val[2];
291
-
292
-	switch(argc)
293
-	{
294
-		case 0:
295
-			*addr = rip;
296
-			break;
297
-		case 1:
298
-			if(addr_expr_val(argv[0], rip, addr) < 0)
299
-			{
300
-				int err = errno;
301
-				asmsh_log_error("Invalid expression value '%s': %s",
302
-						argv[0], strerror(errno));
303
-				errno = err;
304
-				return -1;
305
-			}
306
-			break;
307
-		case 3:
308
-
309
-			for(int i=0; i<2; i++)
310
-			{
311
-				const char *arg = i ? argv[2]:argv[0];
312
-				if(addr_expr_val(arg, rip, &val[i]) < 0)
313
-				{
314
-
315
-					asmsh_log_error("Invalid value '%s' in expression '%s %s %s' : %s",
316
-							arg,
317
-							argv[0], argv[1], argv[2],
318
-							strerror(errno));
319
-					return -1;
320
-				}
321
-			}
322
-
323
-			const char operator = strlen(argv[1]) == 1 ? argv[1][0]: '\0';
324
-			switch(operator)
325
-			{
326
-				case '+':
327
-					*addr = val[0] + val[1];
328
-					break;
329
-				case '-':
330
-					*addr = val[0] - val[1];
331
-					break;
332
-				default:
333
-					asmsh_log_error("Invalid operator '%s' in expression '%s %s %s'",
334
-							argv[1],
335
-							argv[0], argv[1], argv[2]);
336
-					return -1;
337
-			}
338
-			break;
339
-		default:
340
-			//USAGE !
341
-			asmsh_log_error("Unexexpected argument count for an expression. Expecting one of 0, 1 or 3 but got %d", argc);
342
-			return -1;
343
-	}
344
-	return 0;
345
-}

+ 76
- 0
src/shell_cmds.c 파일 보기

224
 	return 0;
224
 	return 0;
225
 }
225
 }
226
 
226
 
227
+
228
+int asmsh_cmd_label(asmsh_t *sh, asmsh_cmd_args_t *args)
229
+{
230
+	const unsigned long rip = sh->env->regs.rip;
231
+
232
+	unsigned long addr;
233
+
234
+	if(args->argc == 0)
235
+	{
236
+		if(sh->env->labels.syms_sz == 0)
237
+		{
238
+			printf("No label defined...\n");
239
+			asmsh_log_info("Use '.label NAME [addr]' to define a label");
240
+			return 0;
241
+		}
242
+		printf("%3ld labels :\n", sh->env->labels.syms_sz);
243
+		for(size_t i=0; i<sh->env->labels.syms_sz; i++)
244
+		{
245
+			printf("\t%c%s\t %016lx\n",
246
+					ASMSH_LABEL_SYM,
247
+					sh->env->labels.syms[i].name,
248
+					sh->env->labels.syms[i].addr);
249
+		}
250
+		return 0;
251
+	}
252
+	if(args->argc == 1)
253
+	{
254
+		addr = rip;
255
+	}
256
+	else
257
+	{
258
+		if(asmsh_cmd_parse_addr_expr(args, 1, rip, &addr) < 0)
259
+		{
260
+			asmsh_log_addr_expr_usage();
261
+			return -1;
262
+		}
263
+	}
264
+
265
+	int ret;
266
+	const char *label = args->args[0];
267
+	if(addr == 0)
268
+	{
269
+		ret = asmsh_symtable_del(&sh->env->labels, label);
270
+		if(ret < 0)
271
+		{
272
+			asmsh_log_perror("Unable to delete label");
273
+			return -1;
274
+		}
275
+		else if(ret > 0)
276
+		{
277
+			asmsh_log_warning("No label '%c%s'",
278
+					ASMSH_LABEL_SYM, label);
279
+			return -1;
280
+		}
281
+		asmsh_log_info("Label '%c%s' deleted", 
282
+				ASMSH_LABEL_SYM, label);
283
+		return 0;
284
+	}
285
+	ret = asmsh_symtable_add(&sh->env->labels, label, addr);
286
+	if(ret < 0)
287
+	{
288
+		asmsh_log_perror("Unable to add label");
289
+		return -1;
290
+	}
291
+	else if(ret > 0)
292
+	{
293
+		asmsh_log_warning("Label '%c%s' updated to %016x",
294
+				ASMSH_LABEL_SYM, label, addr);
295
+		return 0;
296
+	}
297
+	asmsh_log_info("Label '%c%s' %016lx added",
298
+			ASMSH_LABEL_SYM, label, addr);
299
+	return ret;
300
+}
301
+
302
+
227
 int asmsh_cmd_maps(asmsh_t *sh, asmsh_cmd_args_t *args)
303
 int asmsh_cmd_maps(asmsh_t *sh, asmsh_cmd_args_t *args)
228
 {
304
 {
229
 	if(asmsh_env_update_maps(sh->env) < 0)
305
 	if(asmsh_env_update_maps(sh->env) < 0)

+ 10
- 3
src/shell_cmds.h 파일 보기

34
 typedef struct asmsh_cmd_args_s asmsh_cmd_args_t;
34
 typedef struct asmsh_cmd_args_s asmsh_cmd_args_t;
35
 #include "shell.h"
35
 #include "shell.h"
36
 #include "asm_env.h"
36
 #include "asm_env.h"
37
+#include "shell_cmds_lib.h"
38
+#include "shell_sym.h"
37
 
39
 
38
 /** @return <0 on recoverable error 0 on ok, 1+status on exit */
40
 /** @return <0 on recoverable error 0 on ok, 1+status on exit */
39
 typedef int (asmsh_cmd_f)(asmsh_t*, asmsh_cmd_args_t*);
41
 typedef int (asmsh_cmd_f)(asmsh_t*, asmsh_cmd_args_t*);
82
 
84
 
83
 const char *asmsh_cmd_help(asmsh_t *sh);
85
 const char *asmsh_cmd_help(asmsh_t *sh);
84
 
86
 
85
-
86
 /*
87
 /*
87
  * Commands declaration
88
  * Commands declaration
88
  *
89
  *
93
 // Quit the shell
94
 // Quit the shell
94
 int asmsh_cmd_quit(asmsh_t *sh, asmsh_cmd_args_t *args);
95
 int asmsh_cmd_quit(asmsh_t *sh, asmsh_cmd_args_t *args);
95
 
96
 
96
-// Defined in @file shell_cmd_breakpoint.c
97
+// Defined in @ref shell_cmd_breakpoint.c
97
 int asmsh_cmd_breakpoint(asmsh_t *sh, asmsh_cmd_args_t *args);
98
 int asmsh_cmd_breakpoint(asmsh_t *sh, asmsh_cmd_args_t *args);
98
 
99
 
99
 // Print an instruction bytecode 
100
 // Print an instruction bytecode 
100
 int asmsh_cmd_bcode_(asmsh_t *sh, char *buf, int bufsz, int argc, char **args);
101
 int asmsh_cmd_bcode_(asmsh_t *sh, char *buf, int bufsz, int argc, char **args);
101
 int asmsh_cmd_bcode(asmsh_t *sh, asmsh_cmd_args_t *args);
102
 int asmsh_cmd_bcode(asmsh_t *sh, asmsh_cmd_args_t *args);
102
 
103
 
104
+// Defined in @ref shell_cmd_label.c
105
+int asmsh_cmd_label(asmsh_t* sh, asmsh_cmd_args_t *args);
106
+
103
 int asmsh_cmd_maps(asmsh_t *sh, asmsh_cmd_args_t *args);
107
 int asmsh_cmd_maps(asmsh_t *sh, asmsh_cmd_args_t *args);
104
 
108
 
105
 int asmsh_cmd_print_regs(asmsh_t *sh, asmsh_cmd_args_t *args);
109
 int asmsh_cmd_print_regs(asmsh_t *sh, asmsh_cmd_args_t *args);
124
  */
128
  */
125
 static const asmsh_cmd_t asmsh_CMDS[] = {
129
 static const asmsh_cmd_t asmsh_CMDS[] = {
126
 	{".breakpoint", asmsh_cmd_breakpoint, 3,
130
 	{".breakpoint", asmsh_cmd_breakpoint, 3,
127
-	 ".br(eakpoint)", "[addr]",
131
+	 ".br(eakpoint)", "[add|del|list] [addr]",
128
 	 "Set a breakpoint"},
132
 	 "Set a breakpoint"},
129
 	{".bytecode", asmsh_cmd_bcode, 2,
133
 	{".bytecode", asmsh_cmd_bcode, 2,
130
 	 ".b(ytecode)", "",
134
 	 ".b(ytecode)", "",
135
 	{".help", asmsh_cmd_help_, 2,
139
 	{".help", asmsh_cmd_help_, 2,
136
 	 ".h(elp)","[cmd]",
140
 	 ".h(elp)","[cmd]",
137
 	 "display this help or the help of specified command"},
141
 	 "display this help or the help of specified command"},
142
+	{".label", asmsh_cmd_label, 2,
143
+	 ".l(abel)", "label_name [addr]",
144
+	 "Set a label at given address (or . if none given)"},
138
 	{".maps", asmsh_cmd_maps, 2,
145
 	{".maps", asmsh_cmd_maps, 2,
139
 	 ".m(aps)", "",
146
 	 ".m(aps)", "",
140
 	 "display memory maps"},
147
 	 "display memory maps"},

+ 106
- 0
src/shell_cmds_lib.c 파일 보기

1
+#include "shell_cmds_lib.h"
2
+
3
+/** Utility function for @ref asmsh_cmd_parse_addr_expr() that parse an expression value.
4
+ *
5
+ * An expression can be . for rip value or an unsigned long, possibly in hex, etc
6
+ * @param const char* The value
7
+ * @param unsigned long The value of RIP
8
+ * @param unsigned long* A pointer on the result
9
+ * @return -1 on error else 0
10
+ */
11
+static int addr_expr_val(const char *val, unsigned long rip, unsigned long *res);
12
+
13
+
14
+void asmsh_log_addr_expr_usage()
15
+{
16
+	asmsh_log_info("Expected an address expression of the form A + B or A - B with A and B an integer or '.' (for current RIP value)");
17
+}
18
+
19
+
20
+int asmsh_cmd_parse_addr_expr(asmsh_cmd_args_t *args, int first,
21
+		const unsigned long rip, unsigned long *addr)
22
+{
23
+	char * const * argv = args->args + first;
24
+	const int argc = args->argc - first;
25
+
26
+	unsigned long val[2];
27
+
28
+	switch(argc)
29
+	{
30
+		case 0:
31
+			*addr = rip;
32
+			break;
33
+		case 1:
34
+			if(addr_expr_val(argv[0], rip, addr) < 0)
35
+			{
36
+				int err = errno;
37
+				asmsh_log_error("Invalid expression value '%s': %s",
38
+						argv[0], strerror(errno));
39
+				errno = err;
40
+				return -1;
41
+			}
42
+			break;
43
+		case 3:
44
+
45
+			for(int i=0; i<2; i++)
46
+			{
47
+				const char *arg = i ? argv[2]:argv[0];
48
+				if(addr_expr_val(arg, rip, &val[i]) < 0)
49
+				{
50
+
51
+					asmsh_log_error("Invalid value '%s' in expression '%s %s %s' : %s",
52
+							arg,
53
+							argv[0], argv[1], argv[2],
54
+							strerror(errno));
55
+					return -1;
56
+				}
57
+			}
58
+
59
+			const char operator = strlen(argv[1]) == 1 ? argv[1][0]: '\0';
60
+			switch(operator)
61
+			{
62
+				case '+':
63
+					*addr = val[0] + val[1];
64
+					break;
65
+				case '-':
66
+					*addr = val[0] - val[1];
67
+					break;
68
+				default:
69
+					asmsh_log_error("Invalid operator '%s' in expression '%s %s %s'",
70
+							argv[1],
71
+							argv[0], argv[1], argv[2]);
72
+					return -1;
73
+			}
74
+			break;
75
+		default:
76
+			//USAGE !
77
+			asmsh_log_error("Unexexpected argument count for an expression. Expecting one of 0, 1 or 3 but got %d", argc);
78
+			return -1;
79
+	}
80
+	return 0;
81
+}
82
+
83
+
84
+static int addr_expr_val(const char *val, unsigned long rip, unsigned long *res)
85
+{
86
+	if(strcmp(".", val) == 0)
87
+	{
88
+		*res = rip;
89
+		return 0;
90
+	}
91
+
92
+	char *endptr;
93
+	errno = 0;
94
+	*res = strtoul(val, &endptr, 0);
95
+	if(errno != 0)
96
+	{
97
+		return -1;
98
+	}
99
+	else if(*endptr != '\0')
100
+	{
101
+		errno = EINVAL;
102
+		return -1;
103
+	}
104
+	return 0;
105
+}
106
+

+ 43
- 0
src/shell_cmds_lib.h 파일 보기

1
+/* Copyright Yann Weber <asmsh@yannweb.net>
2
+   This file is part of asmsh.
3
+
4
+   asmsh is free software: you can redistribute it and/or modify it under the
5
+   terms of the GNU General Public License as published by the Free Software
6
+   Foundation, either version 3 of the License, or any later version.
7
+   
8
+   asmsh is distributed in the hope that it will be useful, but WITHOUT ANY
9
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
10
+   FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
11
+   details.
12
+   
13
+   You should have received a copy of the GNU General Public License along
14
+   with asmsh. If not, see <https://www.gnu.org/licenses/>.
15
+*/
16
+#ifndef ASMSH_SHELL_CMDS_LIB_H
17
+#define ASMSH_SHELL_CMDS_LIB_H
18
+#include "config.h"
19
+
20
+#include "logger.h"
21
+#include "shell_cmds.h"
22
+
23
+/** Logs address expression usage */
24
+void asmsh_log_addr_expr_usage();
25
+
26
+
27
+/** Parse an address expression
28
+ *
29
+ * An expression must be of the form A [OP B] with A and B
30
+ * an integer or '.' for current RIP value and OP one of + or -
31
+ *
32
+ * @param asmsh_cmd_args_t* The breakpoint command argument list
33
+ * @param int The first argument of the address expression
34
+ * @param const unsigned long RIP value
35
+ * @param unsigned long* A pointer on the result address
36
+ *
37
+ * @returns -1 on error and 0 if ok
38
+ */
39
+int asmsh_cmd_parse_addr_expr(asmsh_cmd_args_t *args, int first,
40
+		const unsigned long rip,  unsigned long *addr);
41
+
42
+#endif
43
+

+ 6
- 5
src/shell_sym.c 파일 보기

84
 			}
84
 			}
85
 			*/
85
 			*/
86
 			table->syms[i].addr = val;
86
 			table->syms[i].addr = val;
87
-			return 0;
87
+			return 1;
88
 		}
88
 		}
89
 		else if(cmp > 0)
89
 		else if(cmp > 0)
90
 		{
90
 		{
109
 {
109
 {
110
 	if(strlen(name) > ASMSH_VARNAME_MAX)
110
 	if(strlen(name) > ASMSH_VARNAME_MAX)
111
 	{
111
 	{
112
-		return 0;
112
+		return -1;
113
 	}
113
 	}
114
 	int i=0;
114
 	int i=0;
115
 	for(i=0; i<table->syms_sz;  i++)
115
 	for(i=0; i<table->syms_sz;  i++)
119
 	}
119
 	}
120
 	if(i==table->syms_sz)
120
 	if(i==table->syms_sz)
121
 	{
121
 	{
122
-		return 0; // not found
122
+		return 1; // not found
123
 	}
123
 	}
124
 	//if(table->freeval) { free(table->syms[i].val); }
124
 	//if(table->freeval) { free(table->syms[i].val); }
125
 	if(table->syms_sz > i+1)
125
 	if(table->syms_sz > i+1)
133
 					sizeof(*table->syms)*table->alloc);
133
 					sizeof(*table->syms)*table->alloc);
134
 			if(!tmp)
134
 			if(!tmp)
135
 			{
135
 			{
136
-				return 0; // :/
136
+				return -1; // :/
137
 			}
137
 			}
138
 			table->syms = tmp;
138
 			table->syms = tmp;
139
 		}
139
 		}
140
 	}
140
 	}
141
 	table->syms_sz--;
141
 	table->syms_sz--;
142
-	return 1; // 1 deleted
142
+	return 0;
143
 }
143
 }
144
 
144
 
145
 
145
 
161
 	return NULL;
161
 	return NULL;
162
 }
162
 }
163
 
163
 
164
+

+ 9
- 1
src/shell_sym.h 파일 보기

24
 #define ASMSH_VARNAME_MAX 256
24
 #define ASMSH_VARNAME_MAX 256
25
 #define ASMSH_SYMALLOC 64
25
 #define ASMSH_SYMALLOC 64
26
 
26
 
27
+/** The symbol prefixing a label */
28
+#define ASMSH_LABEL_SYM '@'
29
+
27
 typedef struct asmsh_sym_s asmsh_sym_t;
30
 typedef struct asmsh_sym_s asmsh_sym_t;
28
 typedef struct asmsh_symtable_s asmsh_symtable_t;
31
 typedef struct asmsh_symtable_s asmsh_symtable_t;
29
 
32
 
48
 int asmsh_symtable_init(asmsh_symtable_t *table);
51
 int asmsh_symtable_init(asmsh_symtable_t *table);
49
 void asmsh_symtable_clean(asmsh_symtable_t *table);
52
 void asmsh_symtable_clean(asmsh_symtable_t *table);
50
 
53
 
54
+/**
55
+ * @return 1 on update 0 on added -1 on error */
51
 int asmsh_symtable_add(asmsh_symtable_t *table, const char *name, unsigned long val);
56
 int asmsh_symtable_add(asmsh_symtable_t *table, const char *name, unsigned long val);
57
+/**
58
+ * @return 0 on deleted, 1 on not found, -1 on error */
52
 int asmsh_symtable_del(asmsh_symtable_t *table, const char *name);
59
 int asmsh_symtable_del(asmsh_symtable_t *table, const char *name);
60
+/**
61
+ * @return NULL on error or not found else a ref */
53
 const asmsh_sym_t *asmsh_symtable_get(asmsh_symtable_t *table, const char *name);
62
 const asmsh_sym_t *asmsh_symtable_get(asmsh_symtable_t *table, const char *name);
54
 
63
 
55
-
56
 #include "shell.h"
64
 #include "shell.h"
57
 
65
 
58
 #endif
66
 #endif

+ 7
- 7
tests/tests_shell_sym.c 파일 보기

24
 	ck_assert_int_eq(st.syms_sz, 1);
24
 	ck_assert_int_eq(st.syms_sz, 1);
25
 	ck_assert_int_eq(asmsh_symtable_add(&st, "a", 0), 0);
25
 	ck_assert_int_eq(asmsh_symtable_add(&st, "a", 0), 0);
26
 	ck_assert_int_eq(st.syms_sz, 2);
26
 	ck_assert_int_eq(st.syms_sz, 2);
27
-	ck_assert_int_eq(asmsh_symtable_add(&st, "a", 0), 0);
27
+	ck_assert_int_eq(asmsh_symtable_add(&st, "a", 0), 1);
28
 	ck_assert_int_eq(st.syms_sz, 2);
28
 	ck_assert_int_eq(st.syms_sz, 2);
29
 	ck_assert_int_eq(asmsh_symtable_add(&st, "ab", 0), 0);
29
 	ck_assert_int_eq(asmsh_symtable_add(&st, "ab", 0), 0);
30
 	ck_assert_int_eq(st.syms_sz, 3);
30
 	ck_assert_int_eq(st.syms_sz, 3);
37
 
37
 
38
 	asmsh_symtable_t st;
38
 	asmsh_symtable_t st;
39
 	ck_assert_int_eq(asmsh_symtable_init(&st), 0);
39
 	ck_assert_int_eq(asmsh_symtable_init(&st), 0);
40
-	ck_assert_int_eq(asmsh_symtable_del(&st, "a"), 0);
41
-	ck_assert_int_eq(asmsh_symtable_add(&st, "a", 0), 0);
42
 	ck_assert_int_eq(asmsh_symtable_del(&st, "a"), 1);
40
 	ck_assert_int_eq(asmsh_symtable_del(&st, "a"), 1);
41
+	ck_assert_int_eq(asmsh_symtable_add(&st, "a", 0), 0);
43
 	ck_assert_int_eq(asmsh_symtable_del(&st, "a"), 0);
42
 	ck_assert_int_eq(asmsh_symtable_del(&st, "a"), 0);
43
+	ck_assert_int_eq(asmsh_symtable_del(&st, "a"), 1);
44
 	ck_assert_int_eq(asmsh_symtable_add(&st, "a", 0), 0);
44
 	ck_assert_int_eq(asmsh_symtable_add(&st, "a", 0), 0);
45
 	ck_assert_int_eq(asmsh_symtable_add(&st, "b", 0), 0);
45
 	ck_assert_int_eq(asmsh_symtable_add(&st, "b", 0), 0);
46
 	ck_assert_int_eq(asmsh_symtable_add(&st, "c", 0), 0);
46
 	ck_assert_int_eq(asmsh_symtable_add(&st, "c", 0), 0);
47
-	ck_assert_int_eq(asmsh_symtable_del(&st, "d"), 0);
48
-	ck_assert_int_eq(asmsh_symtable_del(&st, "b"), 1);
47
+	ck_assert_int_eq(asmsh_symtable_del(&st, "d"), 1);
49
 	ck_assert_int_eq(asmsh_symtable_del(&st, "b"), 0);
48
 	ck_assert_int_eq(asmsh_symtable_del(&st, "b"), 0);
49
+	ck_assert_int_eq(asmsh_symtable_del(&st, "b"), 1);
50
 	ck_assert_int_eq(asmsh_symtable_add(&st, "b", 0), 0);
50
 	ck_assert_int_eq(asmsh_symtable_add(&st, "b", 0), 0);
51
-	ck_assert_int_eq(asmsh_symtable_del(&st, "a"), 1);
52
 	ck_assert_int_eq(asmsh_symtable_del(&st, "a"), 0);
51
 	ck_assert_int_eq(asmsh_symtable_del(&st, "a"), 0);
52
+	ck_assert_int_eq(asmsh_symtable_del(&st, "a"), 1);
53
 	asmsh_symtable_clean(&st);
53
 	asmsh_symtable_clean(&st);
54
 }
54
 }
55
 END_TEST
55
 END_TEST
65
 	s = asmsh_symtable_get(&st, "a");
65
 	s = asmsh_symtable_get(&st, "a");
66
 	ck_assert_ptr_nonnull(s);
66
 	ck_assert_ptr_nonnull(s);
67
 	ck_assert_int_eq(s->addr, 0);
67
 	ck_assert_int_eq(s->addr, 0);
68
-	ck_assert_int_eq(asmsh_symtable_add(&st, "a", 42), 0);
68
+	ck_assert_int_eq(asmsh_symtable_add(&st, "a", 42), 1);
69
 	s = asmsh_symtable_get(&st, "a");
69
 	s = asmsh_symtable_get(&st, "a");
70
 	ck_assert_ptr_nonnull(s);
70
 	ck_assert_ptr_nonnull(s);
71
 	ck_assert_int_eq(s->addr, 42);
71
 	ck_assert_int_eq(s->addr, 42);

Loading…
취소
저장