1 #include <stdio.h> |
1 #include <stdio.h> |
2 #include <string.h> |
2 #include <string.h> |
3 #include <stdlib.h> |
3 #include <stdlib.h> |
4 #include <ctype.h> |
4 #include <ctype.h> |
5 #include <signal.h> |
5 #include <signal.h> |
|
6 #include <unistd.h> |
|
7 #include <setjmp.h> |
6 |
8 |
7 // defined inline to avoid using the stack, but probably |
9 extern char etext, edata, end; |
8 // the stack is used anyway, since we call other functions |
|
9 #define OUTPUT(step) \ |
|
10 { if (*step == '\0') continue; \ |
|
11 printf("%p: ", step); \ |
|
12 if (isalnum(*step)) putchar(*step); \ |
|
13 else printf("<%02x>", *step); \ |
|
14 putchar('\n'); } |
|
15 |
10 |
16 extern char etext, edata, end; |
11 void strings(const char*, const char*); |
|
12 void segv_handler(int, siginfo_t*, void*); |
|
13 void set_sighandler(int, void (*)(int, siginfo_t*, void*)); |
|
14 |
|
15 static sigjmp_buf env; |
17 |
16 |
18 int main(int argc, char **argv) |
17 int main(int argc, char **argv) |
19 { |
18 { |
20 char *step = NULL; |
19 char* data = malloc(1024); |
21 |
20 strcpy(data, "HALLO HIER IST DER HEAP"); |
22 /* Dieser String (nicht die Variable) liegt im Datensegment */ |
|
23 char *local_hallo = "Hallo"; |
|
24 |
|
25 /* Diese Variable liegt komplett im Datensegement */ |
|
26 static char static_hallo[] = "HALLO"; |
|
27 |
|
28 /* Und diese Variable liegt auch auf dem Stack und hier sollten |
|
29 * wir unseren eventuell uebergebenen Commandline-Parameter finden. |
|
30 */ |
|
31 |
|
32 char argument[1024]; |
|
33 if (argc > 1) { |
|
34 if (strlen(argv[1]) > sizeof(argument) - 1) { |
|
35 fprintf(stderr, "arg1 is too long, maximum is %d bytes\n", sizeof(argument)); |
|
36 exit(EXIT_FAILURE); |
|
37 } |
|
38 strcpy(argument, argv[1]); |
|
39 } |
|
40 else { |
|
41 fputs("need some argument on command line\n", stderr); |
|
42 exit(EXIT_FAILURE); |
|
43 } |
|
44 |
21 |
45 printf("First address beyond:\n"); |
22 printf("First address beyond:\n"); |
46 printf(" program text segment(etext) %10p\n", &etext); |
23 printf(" program text segment(etext) %10p\n", &etext); |
47 printf(" initialized data segment(edata) %10p\n", &edata); |
24 printf(" initialized data segment(edata) %10p\n", &edata); |
48 printf(" uninitialized data segment (end) %10p\n", &end); |
25 printf(" uninitialized data segment (end) %10p\n", &end); |
49 printf(" size: %d\n", &end - &etext); |
26 printf(" size: %d\n", &end - &etext); |
50 printf("-----------------------------------------------\n\n"); |
27 printf("Heap near %10p\n", data); |
|
28 printf("Stack near %10p\n", &argc); |
|
29 printf(" … %10p\n", &data); |
|
30 printf("- <ENTER> -------------------------------------\n\n"); |
51 |
31 |
52 // text bis end ausgeben |
32 getchar(); |
53 puts("- START OF INITIALIZED DATA SEGMENT -------"); |
|
54 for (step = &etext; step < &end; step++) |
|
55 OUTPUT(step); |
|
56 puts("- END OF INITIALIZED DATA SEGMENT -------"); |
|
57 |
33 |
58 char *p = malloc(10000); |
34 set_sighandler(SIGSEGV, segv_handler); |
59 strcpy(p, argv[1]); |
|
60 |
35 |
61 printf("end: %10p\n", &end); |
36 puts("etext -> end"); |
62 printf("malloc: %10p\n", p); |
37 strings(&etext, &end); |
63 printf("local: %10p\n", &step); |
|
64 |
38 |
65 // alles nach end ausgeben: |
39 puts("end -> …"); |
66 for (step = &end; 1; step++) { |
40 strings(&end, NULL); |
67 OUTPUT(step); |
41 |
|
42 puts("heap -> …"); |
|
43 strings(data, NULL); |
|
44 |
|
45 puts("stack -> …"); |
|
46 strings((char*) &argc, NULL); |
|
47 |
|
48 puts("done"); |
|
49 return EXIT_SUCCESS; |
|
50 } |
|
51 |
|
52 /* |
|
53 * No user serviceable parts below this line ☺ |
|
54 */ |
|
55 |
|
56 void strings(const char *a, const char *b) |
|
57 { |
|
58 const char *p = a; |
|
59 |
|
60 /* we try to catch the segv signal using setjmp/longjmp, |
|
61 * the setjmp() returns 0 for first invocation, but *seems* to |
|
62 * return a 2nd time if somebody called longjmp (as we do inside the |
|
63 * signal handler). longjmp() passes the value that magically |
|
64 * appears as a result of setjmp(). |
|
65 * It's really magic ☺ |
|
66 */ |
|
67 |
|
68 if (sigsetjmp(env, 1) == 0) { |
|
69 while (b ? p < b : 1) { |
|
70 if (isprint(*p)) { |
|
71 printf("%p: ", p); |
|
72 while ((b ? p < b : 1) && isprint(*p)) putchar(*p++); |
|
73 putchar('\n'); |
|
74 } |
|
75 |
|
76 const char *p0 = p; |
|
77 printf("%p: … ", p); |
|
78 while ((b ? p < b : 1) && !isprint(*p)) p++; |
|
79 printf("+%d\n", p - p0); |
|
80 } |
68 } |
81 } |
69 |
82 |
|
83 printf("%p: <last usable address>\n", p - 1); |
|
84 } |
70 |
85 |
71 // avoid the warning about unused … |
86 void segv_handler(int signal, siginfo_t *si, void *p) |
72 local_hallo = static_hallo; |
87 { |
|
88 printf("segv at address %p\n", si->si_addr); |
|
89 siglongjmp(env, 1); |
|
90 } |
73 |
91 |
74 return EXIT_SUCCESS; |
92 void set_sighandler(int signal, void (handler)(int, siginfo_t*, void*)) |
|
93 { |
|
94 struct sigaction sa = { }; // weiss gerade nicht, ob das eine |
|
95 // gueltige initialisierung ist |
|
96 // memset(&sa, 0, sizeof(sa)); // <- das geht in jedem Falle |
|
97 |
|
98 sa.sa_flags = SA_SIGINFO; |
|
99 sa.sa_sigaction = handler; |
|
100 if (sigaction(signal, &sa, NULL) < 0) { |
|
101 perror("sigaction"); |
|
102 exit(EXIT_FAILURE); |
|
103 } |
75 } |
104 } |
|
105 |