Parcourir la source

Adds dummy logger + tests and starts the compile

Yann Weber il y a 1 an
Parent
révision
949ca0000e
17 fichiers modifiés avec 1840 ajouts et 60 suppressions
  1. 2
    2
      Makefile.am
  2. 595
    0
      compile.c
  3. 149
    0
      compile.h
  4. 5
    2
      config.h.in
  5. 1
    1
      configure.ac
  6. 229
    0
      logger.c
  7. 113
    0
      logger.h
  8. 66
    27
      mmap_parse.c
  9. 13
    0
      mmap_parse.h
  10. 18
    14
      regen.sh
  11. 0
    9
      tests/Makefile.am
  12. 92
    0
      tests/asmsh_check.h
  13. 14
    5
      tests/regen.sh
  14. 7
    0
      tests/samples/procfs_pid_maps
  15. 189
    0
      tests/tests_compile.c
  16. 249
    0
      tests/tests_logger.c
  17. 98
    0
      tests/tests_mmap.c

+ 2
- 2
Makefile.am Voir le fichier

@@ -1,7 +1,7 @@
1 1
 bin_PROGRAMS = asmsh child
2
-noinst_LIBRARIES = libasmsh.a
2
+noinst_LIBRARIES = libcheck_asmsh.a
3 3
 
4
-libasmsh_a_SOURCES = mmap_parse.c
4
+libcheck_asmsh_a_SOURCES = mmap_parse.c compile.c logger.c
5 5
 
6 6
 asmsh_SOURCES = asmsh.c $(libasmsh_a_SOURCES)
7 7
 child_SOURCES = child.s

+ 595
- 0
compile.c Voir le fichier

@@ -0,0 +1,595 @@
1
+#include "compile.h"
2
+
3
+static void _child_cleanup(asmsh_asmc_child_t *child);
4
+
5
+asmsh_asmc_ctx_t* asmsh_asmc_ctx_default()
6
+{
7
+	char * const args[] = ASMSH_COMPILE_ARGS;
8
+	return asmsh_asmc_ctx(ASMSH_COMPILE_AS, ASMSH_COMPILE_OBJ, args, 1, NULL);
9
+}
10
+
11
+
12
+asmsh_asmc_ctx_t* asmsh_asmc_ctx(const char *progname, \
13
+		const char *result_path, char* const args[], int pre_spawn,
14
+		struct timeval *ctimeout)
15
+{
16
+
17
+	const struct timeval default_timeout = {.tv_sec = 1, .tv_usec = 250000};
18
+	asmsh_asmc_ctx_t *res;
19
+
20
+	int argc; // args count
21
+	int errno_bck; // errno will take this value in err labels
22
+	int tmpfd;
23
+	char *temp_name;
24
+
25
+	int i;
26
+	char * const *ptr;
27
+
28
+	if((res = malloc(sizeof(*res))) == NULL)
29
+	{
30
+		errno_bck =  errno;
31
+		goto err_alloc_res;
32
+	}
33
+	bzero(res, sizeof(res));
34
+
35
+	if(asmsh_asmc_buildarg(progname, result_path, args,
36
+			&res->args, &res->progname, &res->respath) < 0)
37
+	{
38
+		errno_bck = errno;
39
+		goto err_buildarg;
40
+	}
41
+
42
+	res->child.pid = -1;
43
+	res->pre_spawn = pre_spawn?1:0;
44
+	if(res->pre_spawn)
45
+	{
46
+		asmsh_asmc_spawn(res);
47
+	}
48
+
49
+	memcpy(&(res->ctimeout), ctimeout?ctimeout:&default_timeout,
50
+			sizeof(struct timeval));
51
+
52
+	free(temp_name);
53
+	return res;
54
+
55
+err_buildarg:
56
+	free(res);
57
+err_alloc_res:
58
+	errno = errno_bck;
59
+	return NULL;
60
+}
61
+
62
+
63
+void asmsh_asmc_ctx_free(asmsh_asmc_ctx_t *ctx)
64
+{
65
+	pid_t cpid;
66
+	int wstatus;
67
+	char **ptr;
68
+
69
+	if(ctx->child.pid > 0)
70
+	{
71
+		cpid = waitpid(ctx->child.pid, &wstatus, WNOHANG);
72
+		if(cpid != -1 && cpid != 0)
73
+		{
74
+			if(WCOREDUMP(wstatus))
75
+			{
76
+				dprintf(2, "Child %d segfault\n", cpid);
77
+				ctx->child.pid = 0;
78
+			}
79
+			else if(WIFEXITED(wstatus))
80
+			{
81
+				if(WEXITSTATUS(wstatus))
82
+				{
83
+					dprintf(2, "Child exited with status %d\n",
84
+							WEXITSTATUS(wstatus));
85
+				}
86
+				ctx->child.pid = 0;
87
+			}
88
+		}
89
+		if(ctx->child.pid > 0)
90
+		{
91
+			if(kill(ctx->child.pid, SIGKILL) == -1)
92
+			{
93
+				perror("Unable to kill child process");
94
+			}
95
+		}
96
+		ctx->child.pid = 0;
97
+		close(ctx->child.pipe_stdin);
98
+	}
99
+	if(ctx->respath)
100
+	{
101
+		unlink(ctx->respath);
102
+	}
103
+	
104
+	for(ptr = ctx->args; *ptr; ptr++) { free(*ptr); }
105
+	free(ctx->args);
106
+	free(ctx);
107
+}
108
+
109
+
110
+int asmsh_asmc_compile(asmsh_asmc_ctx_t *ctx, const char *instr, asmsh_bytecode_t *res)
111
+{
112
+	char *reason = NULL;
113
+	pid_t wpid;
114
+	int wstatus;
115
+
116
+	if(asmsh_asmc_syntax(instr, &reason) == -1)
117
+	{
118
+		dprintf(2, "Syntax error %s : '%s'\n",
119
+				reason, instr);
120
+		errno = EINVAL;
121
+		return -1;
122
+	}
123
+
124
+	if(!ctx->pre_spawn && asmsh_asmc_spawn(ctx) == -1)
125
+	{
126
+		return -1;
127
+	}
128
+
129
+	wpid = waitpid(ctx->child.pid, &wstatus, WNOHANG);
130
+	if(wpid == -1)
131
+	{
132
+		perror("Unable to check child state");
133
+		ctx->child.pid = -1;
134
+		_child_cleanup(&ctx->child);
135
+		return -1;
136
+	}
137
+	else if (wpid)
138
+	{
139
+		if(WCOREDUMP(wstatus))
140
+		{
141
+			dprintf(2, "Child %d segfault\n", ctx->child.pid);
142
+		}
143
+		else if (WIFEXITED(wstatus))
144
+		{
145
+			dprintf(2, "Child %d exited with status %d\n",
146
+					ctx->child.pid,
147
+					WEXITSTATUS(wstatus));
148
+		}
149
+		else
150
+		{
151
+			dprintf(2, "Child %d in unknown status %d\n",
152
+					ctx->child.pid, wstatus);
153
+			_child_cleanup(&ctx->child);
154
+		}
155
+		return -1;
156
+	}
157
+
158
+
159
+	return asmsh_asmc_compile_unsafe(ctx, instr, res);
160
+}
161
+
162
+int asmsh_asmc_compile_unsafe(asmsh_asmc_ctx_t *ctx, const char *_instr,
163
+		asmsh_bytecode_t *res)
164
+{
165
+	int ret;
166
+	size_t instr_sz;
167
+	pid_t wpid;
168
+	int wstatus, sigfd;
169
+	sigset_t sigfdmask, oldmask;
170
+	fd_set sigset;
171
+	struct timeval stimeout;
172
+	char *instr;
173
+
174
+	sigemptyset(&sigfdmask);
175
+	sigaddset(&sigfdmask, SIGCHLD);
176
+	sigfillset(&sigfdmask);
177
+
178
+	/// TODO : early (context ?) sigprocmask ?
179
+	if((sigprocmask(SIG_BLOCK, &sigfdmask, &oldmask) == -1))
180
+	{
181
+		perror("Unable to sigmask");
182
+		goto err_early;
183
+	}
184
+	if((sigfd = signalfd(-1, &sigfdmask, SFD_NONBLOCK)) == -1)
185
+	{
186
+		perror("Unable to sigfd");
187
+		goto err_sigfd;
188
+	}
189
+
190
+
191
+	instr_sz = strlen(_instr);
192
+	instr = alloca(instr_sz+1);
193
+	memcpy(instr, _instr, instr_sz);
194
+	instr[instr_sz] = '\n';
195
+	instr[instr_sz+1] = '\0';
196
+	instr_sz++;
197
+
198
+	ret = write(ctx->child.pipe_stdin, instr, instr_sz);
199
+	if(ret < 0)
200
+	{
201
+		perror("Unable to send instruction to child process");
202
+		goto err;
203
+	}
204
+	else if(ret < instr_sz)
205
+	{
206
+		asmsh_log_error("Unable to write the whole instruction in one write, bailout !\n");
207
+		close(ctx->child.pipe_stdin);
208
+		goto err;
209
+	}
210
+	close(ctx->child.pipe_stdin);
211
+	close(ctx->child.pipe_stderr);
212
+
213
+	FD_ZERO(&sigset);
214
+	FD_SET(sigfd, &sigset);
215
+
216
+	stimeout = ctx->ctimeout;
217
+	do
218
+	{
219
+		if(select(sigfd+1, &sigset, NULL, NULL, &ctx->ctimeout) == 0)
220
+		{
221
+			//compilation timeout t_t
222
+			asmsh_log_error("Compilation timeout");
223
+			goto err;
224
+		}
225
+
226
+		wpid = waitpid(ctx->child.pid, &wstatus, 0);
227
+	}while(!wpid);
228
+
229
+	if(wpid == -1)
230
+	{
231
+		perror("Unable to wait for as to exit");
232
+		goto err_stderr;
233
+	}
234
+	if(WCOREDUMP(wstatus))
235
+	{
236
+		asmsh_log_error("as segfault will compiling");
237
+		goto err_stderr;
238
+	}
239
+	if(!WIFEXITED(wstatus))
240
+	{
241
+		asmsh_log_error("as didn't exited");
242
+		goto err_stderr;
243
+	}
244
+	if(WEXITSTATUS(wstatus))
245
+	{
246
+		asmsh_log_error("GNU as did not exited with 0 status");
247
+		goto err_stderr;
248
+	}
249
+	if((sigprocmask(SIG_BLOCK, &oldmask, NULL) == -1))
250
+	{
251
+		perror("Unable to restore sigmask");
252
+		goto err;
253
+	}
254
+
255
+	ctx->child.pid = 0;
256
+	if(ctx->pre_spawn && asmsh_asmc_spawn(ctx) == -1)
257
+	{
258
+		perror("Unable to pre-spawn");
259
+		goto err;
260
+	}
261
+	
262
+	return asmh_asmc_bytecode_from_obj(ctx->respath, res);
263
+
264
+
265
+err_stderr:
266
+	// TODO read stderr & log it
267
+err:
268
+	close(sigfd);
269
+err_sigfd:
270
+	sigprocmask(SIG_BLOCK, &oldmask, NULL);
271
+err_early:
272
+	_child_cleanup(&ctx->child);
273
+	return -1;
274
+}
275
+
276
+int asmsh_asmc_spawn(asmsh_asmc_ctx_t *ctx)
277
+{
278
+	int fpid;
279
+	int pipes[2][2];
280
+	int err;
281
+	int i;
282
+
283
+	if(ctx->child.pid > 0)
284
+	{
285
+		errno = EUCLEAN;
286
+		return -1;
287
+	}
288
+
289
+	for(i=0; i<2; i++)
290
+	{
291
+		if(pipe(pipes[i]) == -1)
292
+		{
293
+			goto err_pipe;
294
+		}
295
+	}
296
+	fpid = fork();
297
+	if(fpid == -1)
298
+	{
299
+		err = errno;
300
+		goto err_fork;
301
+	}
302
+	else if (fpid == 0)
303
+	{
304
+		asmsh_asmc_child(pipes, ctx->progname, ctx->args);
305
+	}
306
+
307
+	close(pipes[0][0]);
308
+	close(pipes[1][1]);
309
+
310
+	ctx->child.pid = fpid;
311
+	ctx->child.pipe_stdin = pipes[0][1];
312
+	ctx->child.pipe_stderr = pipes[1][0];
313
+
314
+	return 0;
315
+
316
+err_fork:
317
+	i=1;
318
+err_pipe:
319
+	for(i; i>=0; i--)
320
+	{
321
+		close(pipes[i][0]);
322
+		close(pipes[i][1]);
323
+	}
324
+	errno = err;
325
+	return -1;
326
+}
327
+
328
+
329
+void asmsh_asmc_child(const int std_pipes[2][2], const char *progname, char* const args[])
330
+{
331
+	close(std_pipes[0][1]);
332
+	if(dup2(std_pipes[0][0], 0) < 0)
333
+	{
334
+		perror("Unable to pipe stdin");
335
+		exit(1);
336
+	}
337
+	execvp(progname, args);
338
+	perror("execvp failed");
339
+	close(std_pipes[0][0]);
340
+	exit(2);
341
+}
342
+
343
+
344
+int asmsh_asmc_syntax(const char* instr, char **reason)
345
+{
346
+
347
+#define explain(ptr, reason){\
348
+if(ptr) {\
349
+	*ptr = strdup(reason);\
350
+	if(!*ptr) { \
351
+		int e = errno;\
352
+		perror("Unable to strdup to explain syntax error");\
353
+		errno=e;return -1;}}}
354
+	
355
+	const unsigned char *ptr;
356
+
357
+	switch(*instr)
358
+	{
359
+		case '.':
360
+			explain(reason, "Cannot starts with '.'");
361
+			goto err;
362
+		default:
363
+			break;
364
+	}
365
+
366
+	ptr = instr;
367
+	while(*ptr)
368
+	{
369
+		switch(*ptr)
370
+		{
371
+			case '\n':
372
+			case ';':
373
+			case '#':
374
+				explain(reason, "Contains forbidden char");
375
+				goto err;
376
+			default:
377
+				break;
378
+		}
379
+		if(*ptr < 0x20 || *ptr > 0x7E)
380
+		{
381
+			explain(reason, "Contains char in unexpected value range");
382
+			goto err;
383
+		}
384
+		ptr++;
385
+	}
386
+
387
+	*reason = NULL;
388
+	errno = 0;
389
+	return 0;
390
+err:
391
+	errno = EINVAL;
392
+	return -1;
393
+#undef explain
394
+}
395
+
396
+static void _child_cleanup(asmsh_asmc_child_t *child)
397
+{
398
+	if(child->pid > 0)
399
+	{
400
+		kill(child->pid, SIGKILL);
401
+	}
402
+	if(child->pipe_stdin > 0)
403
+	{
404
+		close(child->pipe_stdin);
405
+	}
406
+	if(child->pipe_stderr > 0)
407
+	{
408
+		close(child->pipe_stderr);
409
+	}
410
+	child->pid = child->pipe_stdin = child->pipe_stderr = -1;
411
+}
412
+
413
+
414
+int asmh_asmc_bytecode_from_obj(const char *objfile, asmsh_bytecode_t *bytecode)
415
+{
416
+	/*TODO parse ELF header instead of harcoded addr ?
417
+	  	at least check if the object file has the expected
418
+	  	size for the whole file.
419
+	   Header parsing is better in case the ELF organisation is
420
+	   platform/version dependent ?
421
+	*/
422
+	// ELF 64 constants
423
+	const int bytecode_sz_off = 0x138;
424
+	const int bytecode_sz_sz = 4;
425
+	const int bytecode_off = 0x40;
426
+
427
+	int fd, err;
428
+	off_t off;
429
+	ssize_t rret;
430
+	unsigned int bytecode_sz;
431
+
432
+	if((fd = open(objfile, O_RDONLY)) < 0)
433
+	{
434
+		perror("Unable to open bytecode's object file");
435
+		return -1;
436
+	}
437
+
438
+	if((off = lseek(fd, bytecode_sz_off, SEEK_SET)) != bytecode_sz_off)
439
+	{
440
+		/// TODO check off
441
+		perror("Unable to seek at bytecode size offset");
442
+		err = errno;
443
+		goto err;
444
+	}
445
+
446
+	if((rret = read(fd, &bytecode_sz, bytecode_sz_sz)) != bytecode_sz_sz)
447
+	{
448
+		err = errno;
449
+		if(rret < 0)
450
+		{
451
+			perror("Unable to read bytecode size");
452
+		}
453
+		else
454
+		{
455
+			dprintf(2, "Unable to read the 4 bytes of the bytecode size\n");
456
+			err = ENODATA;
457
+		}
458
+		goto err;
459
+	}
460
+
461
+	if(bytecode_sz == 0)
462
+	{
463
+		dprintf(2, "Null bytecode size");
464
+		err = ENODATA;
465
+		goto err;
466
+	}
467
+	if(bytecode_sz > sizeof(bytecode->bytes))
468
+	{
469
+		dprintf(2, "Bytecode size invalid, too many bytes (%d)\n",
470
+				bytecode_sz);
471
+		err = ENOBUFS;
472
+		goto err;
473
+	}
474
+	if((off = lseek(fd, bytecode_off, SEEK_SET)) != bytecode_off)
475
+	{
476
+		/// TODO check off
477
+		perror("Unable to seek at bytecode offset");
478
+		err = errno;
479
+		goto err;
480
+	}
481
+
482
+	bytecode->size = bytecode_sz;
483
+	if((rret = read(fd, bytecode->bytes, bytecode_sz)) != bytecode_sz)
484
+	{
485
+		err = errno;
486
+		if(rret < 0)
487
+		{
488
+			perror("Unable to read bytecode");
489
+		}
490
+		else
491
+		{
492
+			dprintf(2, "Unable to read the %d bytes of bytecode\n");
493
+			err = ENODATA;
494
+		}
495
+		goto err;
496
+	}
497
+
498
+	close(fd);
499
+	return 0;
500
+
501
+err:
502
+	close(fd);
503
+	errno = err;
504
+	return -1;
505
+}
506
+
507
+
508
+int asmsh_asmc_buildarg(const char* progname, const char *result_tpl, \
509
+		char *const args_in[],
510
+		char ***args_o, char **progname_o, char **respath_o)
511
+{
512
+	int argc, tmpfd, err, i;
513
+	char *tempname;
514
+	char* const *args_ptr;
515
+
516
+	if((tempname = strdupa(result_tpl)) == NULL)
517
+	{
518
+		return -1;
519
+	}
520
+	if((tmpfd = mkstemp(tempname)) == -1)
521
+	{
522
+		err = errno;
523
+		perror("Unable to create temporary result .o file");
524
+		errno = err;
525
+		return -1;
526
+	}
527
+	close(tmpfd);
528
+
529
+	args_ptr = args_in;
530
+	argc = 0;
531
+	for(i=0;i<2;i++) // here we overflow if args_in was malformed
532
+	{
533
+		while(*args_ptr) { args_ptr++; argc++; }
534
+		args_ptr++;
535
+		argc++;
536
+	}
537
+	if((*args_o = malloc(sizeof(char*)*(argc))) == NULL)
538
+	{
539
+		err = errno;
540
+		perror("unable to allocate compiler args array");
541
+		goto err_malloc;
542
+	}
543
+
544
+	if(((*args_o)[0] = strdup(progname)) == NULL)
545
+	{
546
+		err = errno;
547
+		perror("unable to allocate compiler first argument");
548
+		goto err_progname;
549
+	}
550
+	*progname_o = (*args_o)[0];
551
+	*respath_o = NULL;
552
+
553
+	for(i=1; i<argc-1; i++)
554
+	{
555
+		char *const *tocopy;
556
+		if(args_in[i])
557
+		{
558
+			tocopy = &(args_in[i]);
559
+		}
560
+		else
561
+		{
562
+			tocopy = &tempname;
563
+		}
564
+		(*args_o)[i] = strdup(*tocopy);
565
+		if(!(*args_o)[i])
566
+		{
567
+			perror("Unable to copy compiler args");
568
+			goto err_dupargs;
569
+		}
570
+		if(!args_in[i])
571
+		{
572
+			*respath_o = (*args_o)[i];
573
+		}
574
+	}
575
+	(*args_o)[argc-1] = NULL;
576
+
577
+	return 0;
578
+
579
+err_dupargs:
580
+	i--;
581
+	while(i>0)
582
+	{
583
+		free((*args_o)[i]);
584
+		i--;
585
+	}
586
+
587
+err_progname:
588
+	free(args_o);
589
+	*args_o = NULL;
590
+err_malloc:
591
+	unlink(tempname);
592
+	errno = err;
593
+	return -1;
594
+}
595
+

+ 149
- 0
compile.h Voir le fichier

@@ -0,0 +1,149 @@
1
+#ifndef ASMSH_COMPILE_H
2
+#define ASMSH_COMPILE_H
3
+#include "config.h"
4
+
5
+#include <alloca.h>
6
+#include <errno.h>
7
+#include <fcntl.h>
8
+#include <signal.h>
9
+#include <stdio.h>
10
+#include <stdlib.h>
11
+#include <string.h>
12
+#include <unistd.h>
13
+#include <sys/select.h>
14
+#include <sys/signalfd.h>
15
+#include <sys/types.h>
16
+#include <sys/wait.h>
17
+
18
+#include "logger.h"
19
+
20
+/** Define the default assembler (GNU as) */
21
+#define ASMSH_COMPILE_AS "as"
22
+#define ASMSH_COMPILE_ARGS {"", "-O2", "-f", "-ad", "-o", NULL, "-c", "-", NULL}
23
+#define ASMSH_COMPILE_OBJ "/tmp/asmsh_jit_XXXXXX"
24
+
25
+typedef struct asmsh_asmc_ctx_s asmsh_asmc_ctx_t;
26
+typedef struct asmsh_asmc_child_s asmsh_asmc_child_t;
27
+typedef struct asmsh_bytecode_s asmsh_bytecode_t;
28
+
29
+struct asmsh_asmc_child_s
30
+{
31
+	/** Compiler subprocess PID (waiting code on piped STDIN) */
32
+	pid_t pid;
33
+	/** Write endpoint of subprocess's piped STDIN  */
34
+	int pipe_stdin;
35
+	/** Read endpoint of subprocess's piped STDERR */
36
+	int pipe_stderr;
37
+};
38
+
39
+struct asmsh_asmc_ctx_s
40
+{
41
+	/** NULL terminated list of args for child subprocess,
42
+	 * arg[0] is progname */
43
+	char **args;
44
+	/** Points on args[0] */
45
+	char *progname;
46
+	/** Points on the result path argument (value of -o) */
47
+	char *respath;
48
+
49
+	/** Compilation timeout  */
50
+	struct timeval ctimeout;
51
+
52
+	/** A child, that can be spawn in advance */
53
+	asmsh_asmc_child_t child;
54
+
55
+	/** If true pre spawn childs */
56
+	char pre_spawn;
57
+};
58
+
59
+/** Compilation result, 1 instruction bytecode */
60
+struct asmsh_bytecode_s
61
+{
62
+	/** Instruction bytes */
63
+	unsigned char bytes[15];
64
+	/** Instruction size */
65
+	char size;
66
+};
67
+
68
+/**
69
+ * Check if :
70
+ * - contains no ';' nor '#' nor '\n'
71
+ * - only contains char in range [0x20 .. 0x7E]
72
+ * - do not begins by '.'
73
+ *
74
+ * @param char* The instruction to pre-check
75
+ * @param char** If not null contains a reason on failure (and must be freed)
76
+ * @return 0 if instr has a valid syntax else -1
77
+ */
78
+int asmsh_asmc_syntax(const char* instr, char **reason);
79
+
80
+/** Return a default compilation context */
81
+asmsh_asmc_ctx_t* asmsh_asmc_ctx_default();
82
+
83
+/** Return a new compilation context
84
+ * @param char* The assembler name/path
85
+ * @param char* The result path for the compiled obj as mkstemp(3) template
86
+ * @param char*[] The assembler list of arguments, without the argv[0] progname and with NULL as a placeholder for the result path
87
+ * @param int If 0 no child are pre-spawned, else a child is spawned in returned context
88
+ * @param struct timeval* Compilation timeout
89
+ */
90
+asmsh_asmc_ctx_t* asmsh_asmc_ctx(const char *progname, \
91
+		const char *result_path, char* const args[], int pre_spawn,
92
+		struct timeval *ctimeout);
93
+
94
+/** Free all compile context resources */
95
+void asmsh_asmc_ctx_free(asmsh_asmc_ctx_t *ctx);
96
+
97
+/** Compile an instruction
98
+ * @param asmsh_asmc_ctx_t* The context
99
+ * @param const char* The instruction to compile
100
+ * @param asmsh_bytecode_t* Pointer on the result struct
101
+ * @return 0 if ok else -1  on failure with errno set
102
+ */
103
+int asmsh_asmc_compile(asmsh_asmc_ctx_t *ctx, const char *instr, asmsh_bytecode_t *res);
104
+
105
+int asmsh_asmc_compile_unsafe(asmsh_asmc_ctx_t *ctx, const char *_instr, asmsh_bytecode_t *res);
106
+
107
+/** Spawn an assembler process child process
108
+ * @return 0 if no error else -1
109
+ */
110
+int asmsh_asmc_spawn(asmsh_asmc_ctx_t *ctx);
111
+
112
+/**Child process main function
113
+ * @param int[2][2] The pipes for stdin and stderr in this order
114
+ * @param *char The path/name of the assembler executable
115
+ * @param *char[] The NULL terminated list of arguments for the assembler
116
+ * @return NEVER
117
+ */
118
+void asmsh_asmc_child(const int std_pipes[2][2], const char *progname, char* const args[]);
119
+
120
+/** Given an object file, extract the "bytecode"
121
+ *
122
+ * Copy the .text segment of an ELF file
123
+ * @param const char* the object file path
124
+ * @param asmsh_bytecode_t* The result bytecode
125
+ *
126
+ * @return 0 if no error else -1
127
+ */
128
+int asmh_asmc_bytecode_from_obj(const char *objfile, asmsh_bytecode_t *bytecode);
129
+
130
+/** Forge compiler arguments.
131
+ *
132
+ * The constructed arguments list will be allocated in args_o.
133
+ * Put progname as first argument, result_tpl will replace the first NULL encountered
134
+ * in the args_in array. args_in is an array of argument, that will be copied in
135
+ * args_o. 
136
+ * @param const char* The compiler name/path
137
+ * @param const char* An mkstemp() file template
138
+ * @param char *const[] The NULL terminated list of arguments, the first will
139
+ * 	be replaced by the progname value. And the first encountered NULL will
140
+ * 	be affected to the temporary result file (from result_tpl)
141
+ * @param char** The resulting args
142
+ * @return 0 if no error else -1
143
+ */
144
+int asmsh_asmc_buildarg(const char* progname, const char *result_tpl, \
145
+		char *const args_in[],
146
+		char ***args_o, char **progname_o, char **respath_o);
147
+
148
+
149
+#endif

+ 5
- 2
config.h.in Voir le fichier

@@ -9,6 +9,9 @@
9 9
 /* Define to 1 if you have the `fork' function. */
10 10
 #undef HAVE_FORK
11 11
 
12
+/* Define to 1 if you have the `gmtime_r' function. */
13
+#undef HAVE_GMTIME_R
14
+
12 15
 /* Define to 1 if you have the <inttypes.h> header file. */
13 16
 #undef HAVE_INTTYPES_H
14 17
 
@@ -38,8 +41,8 @@
38 41
 /* Define to 1 if you have the <string.h> header file. */
39 42
 #undef HAVE_STRING_H
40 43
 
41
-/* Define to 1 if you have the `strtoull' function. */
42
-#undef HAVE_STRTOULL
44
+/* Define to 1 if you have the `strtoull,' function. */
45
+#undef HAVE_STRTOULL_
43 46
 
44 47
 /* Define to 1 if you have the <sys/stat.h> header file. */
45 48
 #undef HAVE_SYS_STAT_H

+ 1
- 1
configure.ac Voir le fichier

@@ -62,7 +62,7 @@ AC_TYPE_SIZE_T
62 62
 AC_FUNC_FORK
63 63
 AC_FUNC_MALLOC
64 64
 AC_FUNC_REALLOC
65
-AC_CHECK_FUNCS([bzero strtoull])
65
+AC_CHECK_FUNCS([bzero strtoull, gmtime_r])
66 66
 
67 67
 AC_CONFIG_FILES([Makefile tests/Makefile])
68 68
 AC_OUTPUT

+ 229
- 0
logger.c Voir le fichier

@@ -0,0 +1,229 @@
1
+#include "logger.h"
2
+
3
+asmsh_logger_t *_default_logger=NULL;
4
+
5
+int asmsh_logger_setup(asmsh_logger_t *logger)
6
+{
7
+	if(logger)
8
+	{
9
+		_default_logger = logger;
10
+		return 0;
11
+	}
12
+	_default_logger = asmsh_logger_new(ASMSH_WARN);
13
+
14
+	return (_default_logger == NULL) ? -1 : 0;
15
+}
16
+
17
+
18
+asmsh_logger_t* asmsh_logger_new(asmsh_loglevel_t min_level)
19
+{
20
+	asmsh_logger_t *res;
21
+	int err;
22
+
23
+	if((res = malloc(sizeof(*res))) == NULL)
24
+	{
25
+		err = errno;
26
+		dprintf(2, "Error allocating logger");
27
+		errno = err;
28
+		return NULL;
29
+	}
30
+	if((res->msgs = malloc(ASMSH_LOG_BUFFER_ALLOC)) == NULL)
31
+	{
32
+		err = errno;
33
+		dprintf(2, "Error allocating logger's buffer");
34
+		goto err_msgs;
35
+	}
36
+	res->min_level = min_level;
37
+	res->msgs_sz = 0;
38
+	res->msgs_alloc = ASMSH_LOG_BUFFER_ALLOC;
39
+	res->nxt = res->msgs;
40
+
41
+	return res;
42
+
43
+err_msgs:
44
+	free(res);
45
+	errno = err;
46
+	return NULL;
47
+}
48
+
49
+
50
+void asmsh_logger_free(asmsh_logger_t* logger)
51
+{
52
+	if(logger->msgs) { free(logger->msgs); }
53
+	free(logger);
54
+}
55
+
56
+int asmsh_logger_dprint(int fd, asmsh_logger_t *logger)
57
+{
58
+	const int BUF_ALLOC = 4096;
59
+	char *buf;
60
+	int bufsz, ret, res;
61
+	asmsh_log_msg_t *cur;
62
+
63
+	if((buf = malloc(BUF_ALLOC)) == NULL)
64
+	{
65
+		return -1;
66
+	}
67
+	bufsz = BUF_ALLOC;
68
+
69
+	cur = (asmsh_log_msg_t*)logger->msgs;
70
+	res = 0;
71
+	while(cur != logger->nxt)
72
+	{
73
+		ret = asmsh_log_default_fmt(cur, buf, bufsz);
74
+		if(ret < 0)
75
+		{
76
+			perror("Unable to format log message");
77
+			continue;
78
+		}
79
+		else if (ret == BUF_ALLOC)
80
+		{
81
+			buf[BUF_ALLOC-1] = '\0';
82
+			for(int i=0; i<3; i++)
83
+			{
84
+				buf[BUF_ALLOC-(2+i)] = '.';
85
+			}
86
+		}
87
+		res += dprintf(fd, buf); /// TODO check result
88
+		cur = cur->nxt;
89
+	}
90
+	free(buf);
91
+	return res;
92
+}
93
+
94
+int asmsh_logger_strdup(asmsh_logger_t *logger, char **result, size_t *res_sz)
95
+{
96
+	const int BUF_ALLOC = 4096;
97
+	size_t buf_sz;
98
+	asmsh_log_msg_t *cur;
99
+	char *buf_ptr;
100
+	int ret;
101
+
102
+	*res_sz = 0;
103
+	buf_ptr = *result = malloc(buf_sz = BUF_ALLOC);
104
+	if(*result == NULL)
105
+	{
106
+		perror("Enable to allocate buffer for log messages");
107
+		return -1;
108
+	}
109
+
110
+	cur = (asmsh_log_msg_t*)logger->msgs;
111
+	while(cur != logger->nxt)
112
+	{
113
+		ret = asmsh_log_default_fmt(cur, buf_ptr, buf_sz - *res_sz);
114
+		if(ret == (*res_sz - buf_sz))
115
+		{
116
+			buf_sz += BUF_ALLOC;
117
+			void *tmp = realloc(*result, buf_sz);
118
+		}
119
+		else
120
+		{
121
+			*res_sz += ret;
122
+			cur = cur->nxt;
123
+		}
124
+	}
125
+}
126
+
127
+int asmsh_log(asmsh_logger_t *logger, asmsh_loglevel_t lvl, const char caller[],
128
+		const char *msg)
129
+{
130
+	if(!logger)
131
+	{
132
+		logger = _default_logger = asmsh_logger_new(ASMSH_TRACE);
133
+	}
134
+	if(lvl < logger->min_level) { return 0; }
135
+
136
+	size_t caller_len, msg_len, total_len;
137
+
138
+	caller_len = strlen(caller);
139
+	msg_len = strlen(msg);
140
+	total_len = msg_len  + caller_len + 2 + sizeof(asmsh_log_msg_t);
141
+
142
+	if(logger->msgs_alloc <= logger->msgs_sz + total_len)
143
+	{
144
+		void *tmp;
145
+		logger->msgs_alloc += ASMSH_LOG_BUFFER_ALLOC;
146
+		tmp = realloc(logger->msgs, logger->msgs_alloc);
147
+		if(tmp <= 0)
148
+		{
149
+			return -1;
150
+		}
151
+		if(tmp != logger->msgs)
152
+		{
153
+			logger->nxt = tmp + ((void*)logger->nxt - (void*)logger->msgs);
154
+		}
155
+		logger->msgs = tmp;
156
+	}
157
+	if(logger->msgs_alloc <= logger->msgs_sz + total_len)
158
+	{
159
+		// still to short just after realloc, more than
160
+		// ASMSH_LOG_BUFFER_ALLOC is needed, something seems
161
+		// to be wrong
162
+		errno = EMSGSIZE;
163
+		return -1;
164
+	}
165
+
166
+	logger->msgs_sz += total_len;
167
+
168
+	logger->nxt->level = lvl;
169
+	if(time(&(logger->nxt->timestamp)) < 0)
170
+	{
171
+		return -1;
172
+	}
173
+	logger->nxt->caller = (char*)((logger->nxt)+1);
174
+	logger->nxt->msg = logger->nxt->caller + caller_len + 1;
175
+
176
+	strncpy(logger->nxt->caller, caller, caller_len+1);
177
+	strncpy(logger->nxt->msg, msg, msg_len+1);
178
+
179
+	logger->nxt->nxt = (asmsh_log_msg_t*)((void*)logger->nxt->msg+total_len);
180
+	logger->nxt = logger->nxt->nxt;
181
+
182
+	return 0;
183
+
184
+}
185
+
186
+const char * asmsh_loglevel_name(asmsh_loglevel_t lvl)
187
+{
188
+	switch(lvl)
189
+	{
190
+		case ASMSH_TRACE:
191
+			return "TRACE";
192
+		case ASMSH_DEBUG:
193
+			return "DEBUG";
194
+		case ASMSH_INFO:
195
+			return "INFO";
196
+		case ASMSH_WARN:
197
+			return "WARN";
198
+		case ASMSH_ERR:
199
+			return "ERR";
200
+		case ASMSH_FATAL:
201
+			return "FATAL";
202
+		default:
203
+			return "UNKNW";
204
+	}
205
+}
206
+
207
+int asmsh_log_default_fmt(asmsh_log_msg_t *msg, char *res, int sz)
208
+{
209
+	int ret;
210
+	struct tm msg_tm;
211
+	char dtstr[32];
212
+
213
+	if(gmtime_r(&msg->timestamp, &msg_tm) == NULL)
214
+	{
215
+		strncpy(res, "DATETIME ERROR", sz);
216
+		return -1;
217
+	}
218
+
219
+	if(strftime(dtstr, sizeof(dtstr), "%FT%H:%M:%S+00:00", &msg_tm) == 0)
220
+	{
221
+		strncpy(res, "DATETIME FMT ERROR", sz);
222
+		return -1;
223
+	}
224
+
225
+	ret = snprintf(res, sz, "%s [%s](%s) : %s\n",
226
+			dtstr, asmsh_loglevel_name(msg->level),
227
+			msg->caller, msg->msg);
228
+	return ret;
229
+}

+ 113
- 0
logger.h Voir le fichier

@@ -0,0 +1,113 @@
1
+#ifndef ASMSH_LOGGER_H
2
+#define ASMSH_LOGGER_H
3
+#include "config.h"
4
+/** A logger suitable for a shell
5
+ *
6
+ * Collect messages and deliver them when needed
7
+ */
8
+
9
+#include <errno.h>
10
+#include <stdio.h>
11
+#include <stdlib.h>
12
+#include <string.h>
13
+#include <time.h>
14
+
15
+///! TODO varargs macro & log functions, perror etc.
16
+#define asmsh_log_trace(msg) \
17
+	asmsh_log(_default_logger, ASMSH_TRACE, __FUNCTION__, msg)
18
+#define asmsh_log_debug(msg) \
19
+	asmsh_log(_default_logger, ASMSH_DEBUG, __FUNCTION__, msg)
20
+#define asmsh_log_info(msg) \
21
+	asmsh_log(_default_logger, ASMSH_INFO, __FUNCTION__, msg)
22
+#define asmsh_log_warning(msg) \
23
+	asmsh_log(_default_logger, ASMSH_WARN, __FUNCTION__, msg)
24
+#define asmsh_log_error(msg) \
25
+	asmsh_log(_default_logger, ASMSH_ERR, __FUNCTION__, msg)
26
+#define asmsh_log_fatal(msg) \
27
+	asmsh_log(_default_logger, ASMSH_FATAL, __FUNCTION__, msg)
28
+
29
+#define ASMSH_LOG_BUFFER_ALLOC 4096
30
+
31
+typedef struct asmsh_logger_s asmsh_logger_t;
32
+typedef struct asmsh_log_msg_s asmsh_log_msg_t;
33
+typedef enum asmsh_loglevel_e asmsh_loglevel_t;
34
+
35
+extern asmsh_logger_t *_default_logger;
36
+
37
+
38
+enum asmsh_loglevel_e
39
+{
40
+	ASMSH_TRACE = 0,
41
+	ASMSH_DEBUG = 10,
42
+	ASMSH_INFO = 20,
43
+	ASMSH_WARN = 30,
44
+	ASMSH_ERR = 40,
45
+	ASMSH_FATAL = 50
46
+};
47
+
48
+
49
+struct asmsh_log_msg_s
50
+{
51
+	asmsh_loglevel_t level;
52
+	time_t timestamp;
53
+	char *caller;
54
+	char *msg;
55
+	asmsh_log_msg_t *nxt;
56
+};
57
+
58
+
59
+struct asmsh_logger_s
60
+{
61
+	asmsh_loglevel_t min_level;
62
+	/** Buffered messages
63
+	 * 
64
+	 * A single buffer is used to store asmsh_log_msg_t and the
65
+	 * associated strings (caller & msg)
66
+	 * msgs will be a sequence of [asmsh_log_msg_t][char*(caller)][char*(msg)]...
67
+	 */
68
+	void *msgs;
69
+	/** Point on the address of the next message */
70
+	asmsh_log_msg_t *nxt;
71
+	/** Memory used by stored messages */
72
+	size_t msgs_sz;
73
+	/** Allocated buffer for messages */
74
+	size_t msgs_alloc;
75
+};
76
+
77
+
78
+static inline int asmsh_logger_msg_islast(asmsh_logger_t *logger, asmsh_log_msg_t *msg) {
79
+	return ((void*)msg) == ((void*)logger->nxt);
80
+}
81
+
82
+
83
+static inline int asmsh_logger_empty(asmsh_logger_t *logger) {
84
+	return asmsh_logger_msg_islast(logger, (asmsh_log_msg_t*)logger->msgs);
85
+}
86
+
87
+
88
+/** If null use default min_level of WARN
89
+ * @param asmsh_logger_t* Optionnal logger to set
90
+ * @return 0 if ok else -1
91
+ */
92
+int asmsh_logger_setup(asmsh_logger_t *logger);
93
+
94
+asmsh_logger_t* asmsh_logger_new(asmsh_loglevel_t min_level);
95
+
96
+void asmsh_logger_free(asmsh_logger_t* logger);
97
+
98
+int asmsh_logger_dprint(int fd, asmsh_logger_t *logger);
99
+
100
+/// Collect & format messages before printing them on stderr
101
+static inline int asmsh_logger_stderr(asmsh_logger_t *logger) {
102
+	return asmsh_logger_dprint(2, logger);
103
+}
104
+
105
+
106
+int asmsh_log(asmsh_logger_t *logger, asmsh_loglevel_t lvl, const char caller[], const char *msg);
107
+
108
+
109
+const char * asmsh_loglevel_name(asmsh_loglevel_t lvl);
110
+
111
+int asmsh_log_default_fmt(asmsh_log_msg_t *msg, char *res, int sz);
112
+
113
+#endif

+ 66
- 27
mmap_parse.c Voir le fichier

@@ -2,13 +2,8 @@
2 2
 
3 3
 int child_mmap_get(pid_t child_pid, child_mmap_l *maps)
4 4
 {
5
-	const int RDBUF_SZ = 4095;
6 5
 	char procfs_path[PATH_MAX+1];
7
-	char rdbuf[RDBUF_SZ+1];
8
-	char *line, *endline;
9 6
 	int ret, maps_fd;
10
-	size_t curmap;
11
-	void *tmp;
12 7
 	
13 8
 	if(child_pid == -1)
14 9
 	{
@@ -25,12 +20,41 @@ int child_mmap_get(pid_t child_pid, child_mmap_l *maps)
25 20
 		return -1;
26 21
 	}
27 22
 
23
+	if(child_mmap_get_fd(maps_fd, maps) < 0)
24
+	{
25
+		ret = -1;
26
+	}
27
+	else
28
+	{
29
+		ret = 0;
30
+	}
31
+
32
+	close(maps_fd);
33
+	return ret;
34
+
35
+err:
36
+	ret = errno;
37
+	close(maps_fd);
38
+	errno = ret;
39
+	return -1;
40
+}
41
+
42
+int child_mmap_get_fd(int maps_fd, child_mmap_l *maps)
43
+{
44
+	const int RDBUF_SZ = 4095;
45
+	char rdbuf[RDBUF_SZ+1];
46
+	char *line, *endline;
47
+	int ret;
48
+	size_t curmap;
49
+	void *tmp;
50
+	
28 51
 	curmap = 0;
29 52
 
30 53
 	do
31 54
 	{
32 55
 		ret = read(maps_fd, rdbuf, RDBUF_SZ);
33 56
 		if(ret < 0) { goto err; }
57
+		else if(ret == 0) { break; }
34 58
 		rdbuf[ret] = '\0';
35 59
 		line = endline = rdbuf;
36 60
 		while(*endline)
@@ -49,6 +73,7 @@ int child_mmap_get(pid_t child_pid, child_mmap_l *maps)
49 73
 				ret = child_mmap_parseline(line, &maps->maps[curmap]);
50 74
 				if(ret < 0) { goto err; }
51 75
 				line = endline + 1;
76
+				curmap++;
52 77
 			}
53 78
 			endline++;
54 79
 		}
@@ -58,18 +83,18 @@ int child_mmap_get(pid_t child_pid, child_mmap_l *maps)
58 83
 
59 84
 	if(curmap < maps->size)
60 85
 	{
86
+		dprintf(2, "debug realloc : %d %d\n", curmap, maps->size);
61 87
 		tmp = realloc(maps->maps, sizeof(child_mmap_t) * curmap);
62 88
 		if(!tmp)
63 89
 		{
90
+			perror("err");
64 91
 			goto err;
65 92
 		}
66 93
 		maps->maps = tmp;
67 94
 		maps->size = curmap;
68 95
 	}
69 96
 
70
-
71 97
 	return 0;
72
-
73 98
 err:
74 99
 	ret = errno;
75 100
 	close(maps_fd);
@@ -83,6 +108,7 @@ int child_mmap_parseline(char *line, child_mmap_t *maps)
83 108
 	unsigned long long parsed;
84 109
 	int errno_bck, cperm;
85 110
 	size_t i;
111
+	int major;
86 112
 
87 113
 	void **addr_ptr[2] = {&maps->start, &maps->stop};
88 114
 	const char addr_sep[2] = "- ";
@@ -90,29 +116,23 @@ int child_mmap_parseline(char *line, child_mmap_t *maps)
90 116
 	const int perms_val[3] = {PROT_READ, PROT_WRITE, PROT_EXEC};
91 117
 
92 118
 #define parsefield(line, sep, base, mapfield) {\
93
-unsigned long long p; char *endptr;\
94
-errno = 0;\
95
-p = strtoull(line, &endptr, base);\
96
-if(errno || *endptr != sep) { goto err_inval; }\
97
-*mapfield=p;
98
-
99
-
119
+	unsigned long long p; char *endptr;\
120
+	errno = 0;\
121
+	p = strtoull(*line, &endptr, base);\
122
+	if(errno || *endptr != sep) {\
123
+		dprintf(2, "*line : '%s' %s\n", *line, #mapfield);\
124
+		if(errno != ERANGE) { errno=EINVAL; }\
125
+		goto err_inval;\
126
+	}\
127
+	*mapfield=(typeof(*mapfield))p;\
128
+	*line = endptr+1;\
129
+}
130
+	
100 131
 	ptr = orig = line;
101 132
 
102
-	for(i=0; i<2; i++)
103
-	{
104
-		errno = 0;
105
-		parsed = strtoull(line, &endptr, 16);
106
-		if(errno || *endptr != addr_sep[i])
107
-		{
108
-			goto err_inval;
109
-		}
110
-
111
-		*addr_ptr[i] = (void*)parsed;
133
+	parsefield(&line, '-', 16, &maps->start);
134
+	parsefield(&line, ' ', 16, &maps->stop);
112 135
 
113
-		line = endptr+1;
114
-	}
115
-	
116 136
 	cperm = 1;
117 137
 	maps->perm = 0;
118 138
 	for(i=0; i<3; i++)
@@ -142,6 +162,25 @@ if(errno || *endptr != sep) { goto err_inval; }\
142 162
 
143 163
 	line++;
144 164
 
165
+	parsefield(&line, ' ', 16, &maps->offset);
166
+	parsefield(&line, ':', 10, &major);
167
+	parsefield(&line, ' ', 10, &maps->device);
168
+	maps->device |= major << 8; // WARNING : hardcoded major shift
169
+	//parsefield(&line, ' ', 10, &maps->inode);
170
+
171
+	errno = 0;
172
+	parsed = strtoull(line, &endptr, 10);
173
+	if(errno || (*endptr != ' ' && *endptr != '\0'))
174
+	{
175
+		if(errno != ERANGE) { errno = EINVAL; }
176
+		goto err_inval;
177
+	}
178
+	maps->inode = parsed;
179
+	line = endptr;
180
+
181
+	while(*line==' ') { line++; }
182
+
183
+	maps->pathname = strndup(line, PATH_MAX * 8);
145 184
 
146 185
 	return 0;
147 186
 

+ 13
- 0
mmap_parse.h Voir le fichier

@@ -1,6 +1,8 @@
1 1
 #ifndef ASMSH_MMAP_PARSE_H
2 2
 #define ASMSH_MMAP_PARSE_H
3 3
 
4
+#include "config.h"
5
+
4 6
 #include <sys/mman.h>
5 7
 #include <sys/types.h>
6 8
 #include <sys/stat.h>
@@ -9,8 +11,10 @@
9 11
 #include <limits.h>
10 12
 #include <stdlib.h>
11 13
 #include <stdio.h>
14
+#include <string.h>
12 15
 #include <unistd.h>
13 16
 
17
+
14 18
 extern int errno;
15 19
 
16 20
 typedef struct child_mmap_s child_mmap_t;
@@ -41,6 +45,15 @@ struct child_mmap_list
41 45
  */
42 46
 int child_mmap_get(pid_t child_pid, child_mmap_l *maps);
43 47
 
48
+/** Parse an opened /proc/[pid]/map file
49
+ *
50
+ * @param int opened file descriptor
51
+ * @param child_mmap_l A child map that will be filled with child's mmaps
52
+ * @return 0 if no error else -1
53
+ */
54
+int child_mmap_get_fd(int maps_fd, child_mmap_l *maps);
55
+
56
+
44 57
 
45 58
 int child_mmap_parseline(char *line, child_mmap_t *map);
46 59
 

+ 18
- 14
regen.sh Voir le fichier

@@ -1,18 +1,22 @@
1 1
 #!/bin/sh
2 2
 
3
-make distclean
4
-rm -v ar-lib aclocal.m4 "config.h.in~" compile COPYING depcomp INSTALL install-sh missing test-driver configure Makefile.in tests/Makefile.in 2>/dev/null
5
-rm -vR autom4te.cache/ .deps 2>/dev/null
6 3
 
7
-if [ "$1" =  "--clean" ]
8
-then
9
-	exit 0
10
-fi
4
+case $1
5
+in
6
+	--clean|-c)
7
+		make distclean
8
+		rm -v ar-lib aclocal.m4 "config.h.in~" compile COPYING depcomp INSTALL install-sh missing test-driver configure Makefile.in tests/Makefile.in 2>/dev/null
9
+		rm -vR autom4te.cache/ .deps 2>/dev/null
10
+		exit 0
11
+		;;
12
+	--regen|-r)
13
+		sh tests/regen.sh
14
+		autoreconf
15
+		;;
16
+	--new|-n|*)
17
+		sh tests/regen.sh
18
+		autoheader
19
+		autoreconf -i -m
20
+		;;
21
+esac
11 22
 
12
-sh tests/regen.sh
13
-autoheader
14
-autoreconf -i -m
15
-#automake --add-missing
16
-#autoconf
17
-#automake --add-missing
18
-#autoreconf

+ 0
- 9
tests/Makefile.am Voir le fichier

@@ -1,9 +0,0 @@
1
-TESTS = tests_mmap
2
-check_PROGRAMS = tests_mmap
3
-#noinst_HEADERS = ttail_check.h
4
-EXTRA_DIST = samples
5
-
6
-tests_mmap_SOURCES = tests_mmap.c
7
-tests_mmap_CFLAGS = @CHECK_CFLAGS@
8
-tests_mmap_LDADD = $(top_builddir)/libasmsh.a @CHECK_LIBS@
9
-

+ 92
- 0
tests/asmsh_check.h Voir le fichier

@@ -0,0 +1,92 @@
1
+#ifndef _asmsh_check_h__
2
+#define _asmsh_check_h__
3
+
4
+#include <check.h>
5
+#include <errno.h>
6
+#include <stdio.h>
7
+#include <unistd.h>
8
+#include <libgen.h>
9
+#include <fcntl.h>
10
+#include <sys/types.h>
11
+#include <sys/stat.h>
12
+
13
+/**@brief Start a asmsh test
14
+ *@param const char* suite_str test suite string
15
+ *@param const char* tc_str test case string
16
+ */
17
+#define ASMSH_CHECK_START(suite_str, tc_str) \
18
+Suite * asmsh_test_suite(void) \
19
+{\
20
+	Suite *s;\
21
+	TCase *tc;\
22
+	s = suite_create(suite_str);\
23
+	tc = tcase_create(tc_str);
24
+
25
+
26
+/**@brief Set the setup & teardown fixture
27
+ *@param void (*setup)()
28
+ *@param void (*teardown)()
29
+ */
30
+#define ASMSH_SET_FIXTURE(setup, teardown) \
31
+		tcase_add_checked_fixture(tc, setup, teardown)
32
+/**@brief Add a test function defined using START_TEST(name) { ... } END_TEST
33
+ */
34
+#define ASMSH_ADD_TEST(test) tcase_add_test(tc, test)
35
+#define ASMSH_ADD_LOOP_TEST(test, start, stop) tcase_add_loop_test(tc, test, start, stop);
36
+
37
+/**@brief End a asmsh test */
38
+#define ASMSH_CHECK_END \
39
+	suite_add_tcase(s, tc);\
40
+	return s;\
41
+}\
42
+\
43
+int main(int argc, char **argv) {\
44
+	int n_fail;\
45
+	Suite *su;\
46
+	SRunner *sr;\
47
+	n_fail = chdir(dirname(argv[0])); /* move in ./tests dir */ \
48
+	if(n_fail < 0)\
49
+	{\
50
+		perror("Unable to chdir in tests folder");\
51
+	}\
52
+	su = asmsh_test_suite();\
53
+	sr = srunner_create(su);\
54
+	srunner_set_fork_status(sr, CK_FORK);\
55
+	srunner_run_all(sr, CK_VERBOSE);\
56
+	n_fail = srunner_ntests_failed(sr);\
57
+	srunner_free(sr);\
58
+	return (n_fail == 0) ? EXIT_SUCCESS : EXIT_FAILURE;\
59
+}
60
+
61
+#define ck_assert_printf(test, format, ...) {\
62
+	char _err_msg[512];\
63
+	snprintf(_err_msg, sizeof(char) * 512,format, __VA_ARGS__);\
64
+	ck_assert_msg(test, _err_msg);\
65
+}
66
+
67
+#define close_stdpipe() {\
68
+	close(STDPIPE);\
69
+	STDPIPE = -1;\
70
+}
71
+
72
+#define send_sample_stdpipe(id) {\
73
+	int ret;\
74
+	char buff[1024];\
75
+	while((ret= read(samples_fd[id], buff, 1024)) > 0)\
76
+	{\
77
+		ret = write(STDPIPE, buff, strlen(buff));\
78
+		if(ret < 0)\
79
+		{\
80
+			perror("Unable to write through pipe");\
81
+			ck_abort_msg("Unable to write through pipe");\
82
+		}\
83
+	}\
84
+	if(ret < 0)\
85
+	{\
86
+		perror("Unable to read through pipe");\
87
+		ck_abort_msg("Unable to read through pipe");\
88
+	}\
89
+}
90
+
91
+
92
+#endif

+ 14
- 5
tests/regen.sh Voir le fichier

@@ -7,15 +7,24 @@ progs="$(echo *.c | sed -e 's/\.c / /g' -e 's/\.c$//')"
7 7
 cat << __EOF__ > Makefile.am
8 8
 TESTS = $progs
9 9
 check_PROGRAMS = $progs
10
-#noinst_HEADERS = ttail_check.h
10
+noinst_HEADERS = asmsh_check.h
11 11
 EXTRA_DIST = samples
12
+
13
+TESTLIB_NAME=libcheck_asmsh.a
14
+TESTLIB=\$(top_builddir)/\$(TESTLIB_NAME)
15
+
16
+\$(TESTLIB):
17
+	make -C \$(top_builddir) \$(TESTLIB_NAME)
18
+
19
+.PHONY: \$(TESTLIB)
12 20
 __EOF__
13 21
 
14 22
 for p in $progs
15 23
 do
16
-	echo "
24
+	cat << __EOF__ >> Makefile.am
17 25
 ${p}_SOURCES = ${p}.c
18 26
 ${p}_CFLAGS = @CHECK_CFLAGS@
19
-${p}_LDADD = \$(top_builddir)/libasmsh.a @CHECK_LIBS@
20
-"
21
-done >> Makefile.am
27
+${p}_LDADD = \$(TESTLIB) @CHECK_LIBS@
28
+__EOF__
29
+
30
+done

+ 7
- 0
tests/samples/procfs_pid_maps Voir le fichier

@@ -0,0 +1,7 @@
1
+00400000-00452000 r-xp 00000000 08:02 173521      /usr/bin/dbus-daemon
2
+00651000-00652000 r--p 00051000 08:02 173521      /usr/bin/dbus-daemon
3
+00652000-00655000 rw-p 00052000 08:02 173521      /usr/bin/dbus-daemon
4
+00e03000-00e24000 rw-p 00000000 00:00 0           [heap]
5
+00e24000-011f7000 rw-s 00000000 00:00 0           [heap]
6
+35b1a20000-35b1a21000 rw-p 00020000 13:12 135522  /usr/lib64/ld-2.15.so
7
+35b1a21000-35b1a22000 rw-p 00000000 00:00 0

+ 189
- 0
tests/tests_compile.c Voir le fichier

@@ -0,0 +1,189 @@
1
+#define _GNU_SOURCE
2
+#include <check.h>
3
+#include <errno.h>
4
+#include <stdio.h>
5
+#include <string.h>
6
+#include <unistd.h>
7
+
8
+#include "asmsh_check.h"
9
+#include "compile.h"
10
+
11
+static const char *valid_syntax[] = {
12
+	"mov %rax, %rbx",
13
+	"mov %al, %ah",
14
+	"add 1, %rbx",
15
+};
16
+static const int valid_syntax_sz = sizeof(valid_syntax)/sizeof(*valid_syntax);
17
+
18
+START_TEST(test_syntax_valid)
19
+{
20
+	const char *instr = valid_syntax[_i];
21
+	char *reason = NULL;
22
+	int ret;
23
+
24
+	ret = asmsh_asmc_syntax(instr, &reason);
25
+
26
+	ck_assert_int_eq(ret, 0);
27
+	ck_assert_ptr_null(reason);
28
+}
29
+END_TEST
30
+
31
+static const char *invalid_syntax[] = {
32
+	"mov %rax, %rbx;",
33
+	"mov %al, %ah\n",
34
+	"#add 1, %rbx",
35
+	".section text",
36
+};
37
+static const int invalid_syntax_sz = sizeof(invalid_syntax)/sizeof(*invalid_syntax);
38
+
39
+START_TEST(test_syntax_invalid)
40
+{
41
+	const char *instr = invalid_syntax[_i];
42
+	char *reason = NULL;
43
+	int ret;
44
+
45
+	ret = asmsh_asmc_syntax(instr, &reason);
46
+
47
+	ck_assert_int_eq(ret, -1);
48
+	ck_assert_ptr_nonnull(reason);
49
+	free(reason);
50
+}
51
+END_TEST
52
+
53
+
54
+static char* const bargs0[] = ASMSH_COMPILE_ARGS;
55
+static char* const bargs1[] = { "foo", "bar", NULL, NULL, "poison"};
56
+static char* const* const bargs[] = {bargs0, bargs1};
57
+static const char *bobj[] = {
58
+		ASMSH_COMPILE_OBJ,
59
+		"abcXXXXXX",
60
+};
61
+static const char *basmc[] = {
62
+		ASMSH_COMPILE_AS,
63
+		"cc"
64
+};
65
+static const int buildarg_sz = sizeof(bobj)/sizeof(*bobj);
66
+
67
+
68
+START_TEST(test_buildarg)
69
+{
70
+	char *const *args_in = bargs[_i];
71
+	const char *result_tpl = bobj[_i];
72
+	const char *prgname = basmc[_i];
73
+	int ret;
74
+
75
+	char *progname, *respath;
76
+	char **args;
77
+	int i;
78
+
79
+	ret = asmsh_asmc_buildarg(prgname, result_tpl, args_in,
80
+			&args, &progname, &respath);
81
+	ck_assert_int_eq(ret, 0);
82
+
83
+	ck_assert_ptr_nonnull(respath);
84
+	unlink(respath);
85
+
86
+	ck_assert_ptr_nonnull(args);
87
+	ck_assert_ptr_nonnull(progname);
88
+	
89
+	i=0;
90
+	while(args[i])
91
+	{
92
+		if(i == 0)
93
+		{
94
+			ck_assert_str_eq(progname, args[0]);
95
+			ck_assert_str_eq(progname, prgname);
96
+		}
97
+		else if(args_in[i])
98
+		{
99
+			ck_assert_str_eq(args_in[i], args[i]);
100
+		}
101
+		else
102
+		{
103
+			ck_assert_str_eq(args[i], respath);
104
+		}
105
+		free(args[i]);
106
+		i++;
107
+	}
108
+	ck_assert_ptr_null(args[i]);
109
+	free(args);
110
+}
111
+END_TEST
112
+
113
+START_TEST(test_ctx)
114
+{
115
+	int i;
116
+	const char *_args[] = ASMSH_COMPILE_ARGS;
117
+	const char **args = _args;
118
+	asmsh_asmc_ctx_t *ctx = asmsh_asmc_ctx_default();
119
+
120
+	ck_assert_ptr_nonnull(ctx);
121
+	ck_assert_ptr_nonnull(ctx->respath);
122
+	unlink(ctx->respath);
123
+	ck_assert_ptr_nonnull(ctx->progname);
124
+	ck_assert_str_eq(ctx->args[0], ctx->progname);
125
+
126
+	i=1;
127
+	while(args[i])
128
+	{
129
+		ck_assert_str_eq(ctx->args[i], args[i]);
130
+		i++;
131
+	}
132
+	ck_assert_str_eq(ctx->args[i], ctx->respath);
133
+
134
+	i++;
135
+	while(args[i])
136
+	{
137
+		ck_assert_str_eq(ctx->args[i], args[i]);
138
+		i++;
139
+	}
140
+	ck_assert_ptr_null(ctx->args[i]);
141
+
142
+	asmsh_asmc_ctx_free(ctx);
143
+}
144
+END_TEST
145
+
146
+typedef struct
147
+{
148
+	asmsh_bytecode_t bcode;
149
+	char *instr;
150
+} compile_sample_t;
151
+
152
+static const compile_sample_t comp_samples[] = {
153
+	{{"\x48\x83\xc0\x03\0", 4}, "add $3, %rax"},
154
+	{{"\x48\x89\xc3\0", 3}, "mov %rax, %rbx"},
155
+	{{"\x31\xc0\0", 2}, "xor %rax, %rax"},
156
+	{{"\x53\0", 1}, "push %rbx"},
157
+	{{"\x0f\x05\0", 2}, "syscall"},
158
+};
159
+
160
+static const int comp_samples_sz = sizeof(comp_samples)/sizeof(*comp_samples);
161
+
162
+
163
+START_TEST(test_compile)
164
+{
165
+	int ret;
166
+	asmsh_bytecode_t bcode;
167
+	asmsh_asmc_ctx_t *ctx = asmsh_asmc_ctx_default();
168
+
169
+	ret = asmsh_asmc_compile(ctx, comp_samples[_i].instr, &bcode);
170
+
171
+	ck_assert_int_eq(ret, 0);
172
+	ck_assert_int_eq(bcode.size, comp_samples[_i].bcode.size);
173
+	ck_assert_mem_eq(bcode.bytes, comp_samples[_i].bcode.bytes,
174
+			bcode.size);
175
+	//ck_assert_str_eq(bcode.bytes, comp_samples[_i].bcode.bytes);
176
+
177
+	asmsh_asmc_ctx_free(ctx);
178
+}
179
+END_TEST
180
+
181
+/// TODO loop test on asmsh_asmc_ctx with various args
182
+
183
+ASMSH_CHECK_START("compilation tests", "testing compilation functions")
184
+	ASMSH_ADD_LOOP_TEST(test_buildarg, 0, buildarg_sz);
185
+	ASMSH_ADD_LOOP_TEST(test_syntax_valid, 0, valid_syntax_sz);
186
+	ASMSH_ADD_LOOP_TEST(test_syntax_invalid, 0, invalid_syntax_sz);
187
+	ASMSH_ADD_TEST(test_ctx);
188
+	ASMSH_ADD_LOOP_TEST(test_compile, 0, comp_samples_sz);
189
+ASMSH_CHECK_END

+ 249
- 0
tests/tests_logger.c Voir le fichier

@@ -0,0 +1,249 @@
1
+#define _GNU_SOURCE
2
+#include <check.h>
3
+#include <errno.h>
4
+#include <stdio.h>
5
+#include <string.h>
6
+#include <unistd.h>
7
+
8
+#include "asmsh_check.h"
9
+#include "logger.h"
10
+
11
+START_TEST(test_logger_new)
12
+{
13
+	asmsh_logger_t *logger;
14
+	asmsh_loglevel_t lvls[] = {ASMSH_DEBUG, ASMSH_WARN, ASMSH_FATAL};
15
+
16
+	for(int i = 0; i<sizeof(lvls) / sizeof(*lvls); i++)
17
+	{
18
+		logger = asmsh_logger_new(lvls[i]);
19
+
20
+		ck_assert_ptr_nonnull(logger);
21
+		ck_assert_int_eq((logger->min_level), lvls[i]);
22
+		ck_assert_uint_eq((logger->msgs_sz), 0);
23
+		ck_assert_uint_eq((logger->msgs_alloc), ASMSH_LOG_BUFFER_ALLOC);
24
+
25
+		asmsh_logger_free(logger);
26
+	}
27
+
28
+}
29
+END_TEST
30
+
31
+START_TEST(test_log_default_fmt)
32
+{
33
+	asmsh_log_msg_t msg;
34
+	char buf[4096];
35
+	int ret;
36
+
37
+	msg.level = ASMSH_DEBUG;
38
+	msg.timestamp = 0;
39
+	msg.caller = "TestCaller";
40
+	msg.msg = "foo bar";
41
+	msg.nxt = &msg;
42
+
43
+	ret = asmsh_log_default_fmt(&msg, buf, sizeof(buf));
44
+	if(ret == -1)
45
+	{
46
+		dprintf(2, "log fmt error : '%s'\n", buf);
47
+	}
48
+
49
+	ck_assert_uint_eq(strlen(buf), ret);
50
+	ck_assert_str_eq(buf, "1970-01-01T00:00:00+00:00 [DEBUG](TestCaller) : foo bar\n");
51
+
52
+}
53
+END_TEST
54
+
55
+
56
+START_TEST(test_log_function_lvl_nolog)
57
+{
58
+	asmsh_logger_t *logger;
59
+	asmsh_log_msg_t *msg;
60
+
61
+	logger = asmsh_logger_new(ASMSH_INFO);
62
+
63
+	ck_assert_int_eq(asmsh_log(logger, ASMSH_DEBUG, "caller", "msg"), 0);
64
+
65
+	ck_assert_uint_eq(logger->msgs_alloc, ASMSH_LOG_BUFFER_ALLOC);
66
+	ck_assert_ptr_nonnull(logger->msgs);
67
+	ck_assert_ptr_eq(logger->msgs, logger->nxt);
68
+	ck_assert_int_ne(asmsh_logger_empty(logger), 0);
69
+}
70
+END_TEST
71
+
72
+static const char *msg_samples[][2] = {
73
+	{"caller", "msg"},
74
+	{"superfoofun", "super \"long\" message :P"},
75
+	{"...", "woot"},
76
+};
77
+static const int msg_samples_sz = sizeof(msg_samples)/sizeof(*msg_samples);
78
+
79
+
80
+START_TEST(test_log_function_lvl_singlelog)
81
+{
82
+	asmsh_log_msg_t *msg;
83
+	asmsh_logger_t *logger;
84
+	const char *caller, *testmsg;
85
+	size_t total_len;
86
+
87
+	
88
+	caller = msg_samples[_i][0];
89
+	testmsg = msg_samples[_i][1];
90
+	total_len = sizeof(asmsh_log_msg_t);
91
+	total_len += strlen(caller) + strlen(testmsg) + 2;
92
+
93
+	logger = asmsh_logger_new(ASMSH_INFO);
94
+
95
+	ck_assert_int_eq(asmsh_log(logger, ASMSH_ERR, caller, testmsg), 0);
96
+
97
+	ck_assert_uint_eq(logger->msgs_alloc, ASMSH_LOG_BUFFER_ALLOC);
98
+	ck_assert_ptr_nonnull(logger->msgs);
99
+
100
+	msg = (asmsh_log_msg_t*)logger->msgs;
101
+
102
+	ck_assert_ptr_nonnull(msg->caller);
103
+	ck_assert_ptr_nonnull(msg->msg);
104
+
105
+	ck_assert_str_eq(caller, msg->caller);
106
+	ck_assert_str_eq(testmsg, msg->msg);
107
+
108
+	ck_assert_uint_eq(logger->msgs_sz, total_len);
109
+
110
+	asmsh_logger_free(logger);
111
+}
112
+END_TEST
113
+
114
+
115
+START_TEST(test_log_function_lvl_logs)
116
+{
117
+
118
+	asmsh_log_msg_t *msg;
119
+	asmsh_logger_t *logger;
120
+	logger = asmsh_logger_new(ASMSH_INFO);
121
+
122
+	const char *caller, *testmsg;
123
+	size_t total_len = 0;
124
+
125
+	for(int i=0; i<msg_samples_sz; i++)
126
+	{
127
+		
128
+		caller = msg_samples[i][0];
129
+		testmsg = msg_samples[i][1];
130
+		total_len += sizeof(asmsh_log_msg_t);
131
+		total_len += strlen(caller) + strlen(testmsg) + 2;
132
+
133
+		ck_assert_int_eq(asmsh_log(logger, ASMSH_INFO, caller, testmsg), 0);
134
+	}
135
+
136
+	ck_assert_ptr_nonnull(logger->msgs);
137
+
138
+	msg = (asmsh_log_msg_t*)logger->msgs;
139
+	for(int i=0; i<msg_samples_sz; i++)
140
+	{
141
+		
142
+		caller = msg_samples[i][0];
143
+		testmsg = msg_samples[i][1];
144
+
145
+		ck_assert_ptr_nonnull(msg->caller);
146
+		ck_assert_ptr_nonnull(msg->msg);
147
+		ck_assert_int_eq(msg->level, ASMSH_INFO);
148
+
149
+		ck_assert_str_eq(caller, msg->caller);
150
+		ck_assert_str_eq(testmsg, msg->msg);
151
+
152
+		msg = msg->nxt;
153
+	}
154
+	ck_assert_uint_eq(logger->msgs_sz, total_len);
155
+	asmsh_logger_free(logger);
156
+}
157
+END_TEST
158
+
159
+
160
+START_TEST(test_log_dprint)
161
+{
162
+	asmsh_log_msg_t *msg;
163
+	asmsh_logger_t *logger;
164
+	logger = asmsh_logger_new(ASMSH_INFO);
165
+
166
+	const char *caller, *testmsg;
167
+	char *exptr, *expt, *res;
168
+	size_t total_len = 0;
169
+	int tmp_fd;
170
+	const char _tmpname[] = "/tmp/dprintXXXXXX";
171
+	char *tmpname = strdupa(_tmpname);
172
+
173
+	for(int i=0; i<msg_samples_sz; i++)
174
+	{
175
+		
176
+		caller = msg_samples[i][0];
177
+		testmsg = msg_samples[i][1];
178
+		total_len += sizeof(asmsh_log_msg_t);
179
+		total_len += strlen(caller) + strlen(testmsg) + 2;
180
+
181
+		ck_assert_int_eq(asmsh_log(logger, ASMSH_INFO, caller, testmsg), 0);
182
+	}
183
+	ck_assert_ptr_nonnull(logger->msgs);
184
+
185
+	// forcing time to 1970-01-01T00:00:00+00:00
186
+	msg = logger->msgs;
187
+	while(msg != logger->nxt)
188
+	{
189
+		msg->timestamp = 0;
190
+
191
+		msg = msg->nxt;
192
+	}
193
+
194
+	if((expt = malloc(logger->msgs_alloc)) == NULL)
195
+	{
196
+		perror("Unable to allocate expected result");
197
+		ck_abort_msg("Unable to allocate expt");
198
+	}
199
+	*expt = '\0';
200
+	exptr = expt;
201
+
202
+	for(int i=0; i<msg_samples_sz; i++)
203
+	{
204
+		
205
+		caller = msg_samples[i][0];
206
+		testmsg = msg_samples[i][1];
207
+		int ret = sprintf(exptr,
208
+				"1970-01-01T00:00:00+00:00 [INFO](%s) : %s\n",
209
+				caller, testmsg);
210
+		exptr += ret;
211
+		if(exptr-expt > logger->msgs_alloc)
212
+		{
213
+			ck_abort_msg("WTF");
214
+		}
215
+	}
216
+
217
+	tmp_fd = mkstemp(tmpname);
218
+	
219
+	int printed_sz = asmsh_logger_dprint(tmp_fd, logger);
220
+
221
+
222
+	lseek(tmp_fd, SEEK_SET, 0);
223
+
224
+	if((res = malloc(printed_sz+16)) == NULL)
225
+	{
226
+		perror("Unable to allocate result");
227
+		ck_abort_msg("unable to allocate result");
228
+	}
229
+
230
+	printed_sz = read(tmp_fd, res, printed_sz+15);
231
+	res[printed_sz] = '\0';
232
+	close(tmp_fd);
233
+	unlink(tmpname);
234
+
235
+	ck_assert_str_eq(expt, res);
236
+
237
+	asmsh_logger_free(logger);
238
+}
239
+END_TEST
240
+
241
+
242
+ASMSH_CHECK_START("logger tests", "unit tests various logger function")
243
+	ASMSH_ADD_TEST(test_logger_new);
244
+	ASMSH_ADD_TEST(test_log_default_fmt);
245
+	ASMSH_ADD_TEST(test_log_function_lvl_nolog);
246
+	ASMSH_ADD_LOOP_TEST(test_log_function_lvl_singlelog, 0, msg_samples_sz);
247
+	ASMSH_ADD_TEST(test_log_function_lvl_logs);
248
+	ASMSH_ADD_TEST(test_log_dprint);
249
+ASMSH_CHECK_END

+ 98
- 0
tests/tests_mmap.c Voir le fichier

@@ -0,0 +1,98 @@
1
+#include <check.h>
2
+#include <errno.h>
3
+#include <stdio.h>
4
+#include <string.h>
5
+#include <unistd.h>
6
+
7
+#include "asmsh_check.h"
8
+#include "mmap_parse.h"
9
+
10
+#define PARSE_FD_SAMPLE "samples/procfs_pid_maps"
11
+
12
+typedef struct {
13
+	child_mmap_t map;
14
+	char *line;
15
+} mmap_linecheck_t;
16
+
17
+START_TEST (test_parse_line)
18
+{
19
+	child_mmap_t res;
20
+	size_t i;
21
+
22
+	mmap_linecheck_t lcheck[] = {
23
+		{{(void*)0x123456, (void*)0x654321,
24
+		 MAP_PRIVATE, 0, 0, 0, "[stack]"},
25
+		"123456-654321 ---p 00000000 0:0 0        [stack]"},
26
+		{{(void*)0, (void*)0x1000,
27
+		 PROT_READ | PROT_WRITE | PROT_EXEC | MAP_SHARED,
28
+		 1, (13<<8)+12, 123, "[stack]"},
29
+		"0-01000 rwxs 00000001 13:12 123      [stack]"},
30
+		{{(void*)0x35b1800000, (void*)0x35b1820000,
31
+		 PROT_READ | PROT_EXEC | MAP_PRIVATE, 0x1f000, (8<<8)+2, 135522, "/usr/lib64/ld-2.15.so"},
32
+		"35b1800000-35b1820000 r-xp 0001f000 08:02 135522      /usr/lib64/ld-2.15.so"},
33
+	};
34
+
35
+	for(i=0; i<sizeof(lcheck) / sizeof(mmap_linecheck_t); i++)
36
+	{
37
+		ck_assert_int_eq(child_mmap_parseline(lcheck[i].line, &res), 0);
38
+		ck_assert_ptr_eq(lcheck[i].map.start, res.start);
39
+		ck_assert_ptr_eq(lcheck[i].map.stop, res.stop);
40
+		ck_assert_int_eq(lcheck[i].map.perm, res.perm);
41
+		ck_assert(lcheck[i].map.offset == res.offset);
42
+		ck_assert(lcheck[i].map.device == res.device);
43
+		ck_assert(lcheck[i].map.inode == res.inode);
44
+		ck_assert_str_eq(lcheck[i].map.pathname, res.pathname);
45
+	}
46
+}
47
+END_TEST
48
+
49
+START_TEST (test_parse_fd)
50
+{
51
+	child_mmap_l maps;
52
+	int fd, ret;
53
+
54
+	child_mmap_t checks[] = {
55
+		{(void*)0x400000, (void*)0x452000,
56
+		 PROT_READ | PROT_EXEC | MAP_PRIVATE, 0, (8<<8)+2, 173521,
57
+		 "/usr/bin/dbus-daemon"},
58
+		{(void*)0x651000, (void*)0x652000,
59
+		 PROT_READ | MAP_PRIVATE, 0, (8<<8)+2, 173521,
60
+		 "/usr/bin/dbus-daemon"},
61
+		{(void*)0x652000, (void*)0x655000,
62
+		 PROT_READ | PROT_WRITE | MAP_PRIVATE, 0, (8<<8)+2, 173521,
63
+		 "/usr/bin/dbus-daemon"},
64
+		{(void*)0xe3000, (void*)0xe24000,
65
+		 PROT_READ | PROT_WRITE | MAP_PRIVATE, 0, 0, 0,
66
+		 "[heap]"},
67
+		{(void*)0x24000, (void*)0x11f7000,
68
+		 PROT_READ | PROT_WRITE | MAP_SHARED, 0, 0, 0,
69
+		 "[heap]"},
70
+		{(void*)0x35b1a20000, (void*)0x35b1a21000,
71
+		 PROT_READ | PROT_WRITE | MAP_PRIVATE, 0x20000, (13<<8)+12, 135522,
72
+		 "/usr/lib64/ld-2.15.so"},
73
+		{(void*)0x35b1a21000, (void*)0x35b1a22000,
74
+		 PROT_READ | PROT_WRITE | MAP_PRIVATE, 0x20000, 0, 0,
75
+		 ""},
76
+	};
77
+
78
+	bzero(&maps, sizeof(child_mmap_l));
79
+	fd = open(PARSE_FD_SAMPLE, O_RDONLY);
80
+	if(fd < 0)
81
+	{
82
+		perror("Unable to open sample");
83
+		ck_abort_msg("Unable to open sample");
84
+	}
85
+	
86
+	ret = child_mmap_get_fd(fd, &maps);
87
+
88
+	ck_assert_int_eq(ret, 0);
89
+
90
+	close(fd);
91
+}
92
+END_TEST
93
+
94
+ASMSH_CHECK_START("/proc/[pid]/map file parser", "parsing tests")
95
+	ASMSH_ADD_TEST(test_parse_line);
96
+	ASMSH_ADD_TEST(test_parse_fd);
97
+ASMSH_CHECK_END
98
+

Loading…
Annuler
Enregistrer