aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/trace/ftrace.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/trace/ftrace.c')
-rw-r--r--kernel/trace/ftrace.c208
1 files changed, 101 insertions, 107 deletions
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 369fb78bd4ab..fed1ebc3a133 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -297,6 +297,19 @@ static struct ftrace_page *ftrace_pages;
297 297
298static struct dyn_ftrace *ftrace_free_records; 298static struct dyn_ftrace *ftrace_free_records;
299 299
300/*
301 * This is a double for. Do not use 'break' to break out of the loop,
302 * you must use a goto.
303 */
304#define do_for_each_ftrace_rec(pg, rec) \
305 for (pg = ftrace_pages_start; pg; pg = pg->next) { \
306 int _____i; \
307 for (_____i = 0; _____i < pg->index; _____i++) { \
308 rec = &pg->records[_____i];
309
310#define while_for_each_ftrace_rec() \
311 } \
312 }
300 313
301#ifdef CONFIG_KPROBES 314#ifdef CONFIG_KPROBES
302 315
@@ -341,7 +354,6 @@ void ftrace_release(void *start, unsigned long size)
341 struct ftrace_page *pg; 354 struct ftrace_page *pg;
342 unsigned long s = (unsigned long)start; 355 unsigned long s = (unsigned long)start;
343 unsigned long e = s + size; 356 unsigned long e = s + size;
344 int i;
345 357
346 if (ftrace_disabled || !start) 358 if (ftrace_disabled || !start)
347 return; 359 return;
@@ -349,14 +361,11 @@ void ftrace_release(void *start, unsigned long size)
349 /* should not be called from interrupt context */ 361 /* should not be called from interrupt context */
350 spin_lock(&ftrace_lock); 362 spin_lock(&ftrace_lock);
351 363
352 for (pg = ftrace_pages_start; pg; pg = pg->next) { 364 do_for_each_ftrace_rec(pg, rec) {
353 for (i = 0; i < pg->index; i++) { 365 if ((rec->ip >= s) && (rec->ip < e))
354 rec = &pg->records[i]; 366 ftrace_free_rec(rec);
367 } while_for_each_ftrace_rec();
355 368
356 if ((rec->ip >= s) && (rec->ip < e))
357 ftrace_free_rec(rec);
358 }
359 }
360 spin_unlock(&ftrace_lock); 369 spin_unlock(&ftrace_lock);
361} 370}
362 371
@@ -523,41 +532,37 @@ __ftrace_replace_code(struct dyn_ftrace *rec, int enable)
523 532
524static void ftrace_replace_code(int enable) 533static void ftrace_replace_code(int enable)
525{ 534{
526 int i, failed; 535 int failed;
527 struct dyn_ftrace *rec; 536 struct dyn_ftrace *rec;
528 struct ftrace_page *pg; 537 struct ftrace_page *pg;
529 538
530 for (pg = ftrace_pages_start; pg; pg = pg->next) { 539 do_for_each_ftrace_rec(pg, rec) {
531 for (i = 0; i < pg->index; i++) { 540 /*
532 rec = &pg->records[i]; 541 * Skip over free records and records that have
533 542 * failed.
534 /* 543 */
535 * Skip over free records and records that have 544 if (rec->flags & FTRACE_FL_FREE ||
536 * failed. 545 rec->flags & FTRACE_FL_FAILED)
537 */ 546 continue;
538 if (rec->flags & FTRACE_FL_FREE ||
539 rec->flags & FTRACE_FL_FAILED)
540 continue;
541
542 /* ignore updates to this record's mcount site */
543 if (get_kprobe((void *)rec->ip)) {
544 freeze_record(rec);
545 continue;
546 } else {
547 unfreeze_record(rec);
548 }
549 547
550 failed = __ftrace_replace_code(rec, enable); 548 /* ignore updates to this record's mcount site */
551 if (failed && (rec->flags & FTRACE_FL_CONVERTED)) { 549 if (get_kprobe((void *)rec->ip)) {
552 rec->flags |= FTRACE_FL_FAILED; 550 freeze_record(rec);
553 if ((system_state == SYSTEM_BOOTING) || 551 continue;
554 !core_kernel_text(rec->ip)) { 552 } else {
555 ftrace_free_rec(rec); 553 unfreeze_record(rec);
556 } else
557 ftrace_bug(failed, rec->ip);
558 }
559 } 554 }
560 } 555
556 failed = __ftrace_replace_code(rec, enable);
557 if (failed && (rec->flags & FTRACE_FL_CONVERTED)) {
558 rec->flags |= FTRACE_FL_FAILED;
559 if ((system_state == SYSTEM_BOOTING) ||
560 !core_kernel_text(rec->ip)) {
561 ftrace_free_rec(rec);
562 } else
563 ftrace_bug(failed, rec->ip);
564 }
565 } while_for_each_ftrace_rec();
561} 566}
562 567
563static int 568static int
@@ -956,22 +961,17 @@ static void ftrace_filter_reset(int enable)
956 struct ftrace_page *pg; 961 struct ftrace_page *pg;
957 struct dyn_ftrace *rec; 962 struct dyn_ftrace *rec;
958 unsigned long type = enable ? FTRACE_FL_FILTER : FTRACE_FL_NOTRACE; 963 unsigned long type = enable ? FTRACE_FL_FILTER : FTRACE_FL_NOTRACE;
959 unsigned i;
960 964
961 /* should not be called from interrupt context */ 965 /* should not be called from interrupt context */
962 spin_lock(&ftrace_lock); 966 spin_lock(&ftrace_lock);
963 if (enable) 967 if (enable)
964 ftrace_filtered = 0; 968 ftrace_filtered = 0;
965 pg = ftrace_pages_start; 969 do_for_each_ftrace_rec(pg, rec) {
966 while (pg) { 970 if (rec->flags & FTRACE_FL_FAILED)
967 for (i = 0; i < pg->index; i++) { 971 continue;
968 rec = &pg->records[i]; 972 rec->flags &= ~type;
969 if (rec->flags & FTRACE_FL_FAILED) 973 } while_for_each_ftrace_rec();
970 continue; 974
971 rec->flags &= ~type;
972 }
973 pg = pg->next;
974 }
975 spin_unlock(&ftrace_lock); 975 spin_unlock(&ftrace_lock);
976} 976}
977 977
@@ -1094,44 +1094,39 @@ ftrace_match(unsigned char *buff, int len, int enable)
1094 spin_lock(&ftrace_lock); 1094 spin_lock(&ftrace_lock);
1095 if (enable) 1095 if (enable)
1096 ftrace_filtered = 1; 1096 ftrace_filtered = 1;
1097 pg = ftrace_pages_start; 1097 do_for_each_ftrace_rec(pg, rec) {
1098 while (pg) { 1098 int matched = 0;
1099 for (i = 0; i < pg->index; i++) { 1099 char *ptr;
1100 int matched = 0; 1100
1101 char *ptr; 1101 if (rec->flags & FTRACE_FL_FAILED)
1102 1102 continue;
1103 rec = &pg->records[i]; 1103 kallsyms_lookup(rec->ip, NULL, NULL, NULL, str);
1104 if (rec->flags & FTRACE_FL_FAILED) 1104 switch (type) {
1105 continue; 1105 case MATCH_FULL:
1106 kallsyms_lookup(rec->ip, NULL, NULL, NULL, str); 1106 if (strcmp(str, buff) == 0)
1107 switch (type) { 1107 matched = 1;
1108 case MATCH_FULL: 1108 break;
1109 if (strcmp(str, buff) == 0) 1109 case MATCH_FRONT_ONLY:
1110 matched = 1; 1110 if (memcmp(str, buff, match) == 0)
1111 break; 1111 matched = 1;
1112 case MATCH_FRONT_ONLY: 1112 break;
1113 if (memcmp(str, buff, match) == 0) 1113 case MATCH_MIDDLE_ONLY:
1114 matched = 1; 1114 if (strstr(str, search))
1115 break; 1115 matched = 1;
1116 case MATCH_MIDDLE_ONLY: 1116 break;
1117 if (strstr(str, search)) 1117 case MATCH_END_ONLY:
1118 matched = 1; 1118 ptr = strstr(str, search);
1119 break; 1119 if (ptr && (ptr[search_len] == 0))
1120 case MATCH_END_ONLY: 1120 matched = 1;
1121 ptr = strstr(str, search); 1121 break;
1122 if (ptr && (ptr[search_len] == 0))
1123 matched = 1;
1124 break;
1125 }
1126 if (matched) {
1127 if (not)
1128 rec->flags &= ~flag;
1129 else
1130 rec->flags |= flag;
1131 }
1132 } 1122 }
1133 pg = pg->next; 1123 if (matched) {
1134 } 1124 if (not)
1125 rec->flags &= ~flag;
1126 else
1127 rec->flags |= flag;
1128 }
1129 } while_for_each_ftrace_rec();
1135 spin_unlock(&ftrace_lock); 1130 spin_unlock(&ftrace_lock);
1136} 1131}
1137 1132
@@ -1452,7 +1447,7 @@ ftrace_set_func(unsigned long *array, int idx, char *buffer)
1452 struct dyn_ftrace *rec; 1447 struct dyn_ftrace *rec;
1453 struct ftrace_page *pg; 1448 struct ftrace_page *pg;
1454 int found = 0; 1449 int found = 0;
1455 int i, j; 1450 int j;
1456 1451
1457 if (ftrace_disabled) 1452 if (ftrace_disabled)
1458 return -ENODEV; 1453 return -ENODEV;
@@ -1460,27 +1455,26 @@ ftrace_set_func(unsigned long *array, int idx, char *buffer)
1460 /* should not be called from interrupt context */ 1455 /* should not be called from interrupt context */
1461 spin_lock(&ftrace_lock); 1456 spin_lock(&ftrace_lock);
1462 1457
1463 for (pg = ftrace_pages_start; pg; pg = pg->next) { 1458 do_for_each_ftrace_rec(pg, rec) {
1464 for (i = 0; i < pg->index; i++) { 1459
1465 rec = &pg->records[i]; 1460 if (rec->flags & (FTRACE_FL_FAILED | FTRACE_FL_FREE))
1466 1461 continue;
1467 if (rec->flags & (FTRACE_FL_FAILED | FTRACE_FL_FREE)) 1462
1468 continue; 1463 kallsyms_lookup(rec->ip, NULL, NULL, NULL, str);
1469 1464 if (strcmp(str, buffer) == 0) {
1470 kallsyms_lookup(rec->ip, NULL, NULL, NULL, str); 1465 /* Return 1 if we add it to the array */
1471 if (strcmp(str, buffer) == 0) { 1466 found = 1;
1472 found = 1; 1467 for (j = 0; j < idx; j++)
1473 for (j = 0; j < idx; j++) 1468 if (array[j] == rec->ip) {
1474 if (array[j] == rec->ip) { 1469 found = 0;
1475 found = 0; 1470 break;
1476 break; 1471 }
1477 } 1472 if (found)
1478 if (found) 1473 array[idx] = rec->ip;
1479 array[idx] = rec->ip; 1474 goto out;
1480 break;
1481 }
1482 } 1475 }
1483 } 1476 } while_for_each_ftrace_rec();
1477 out:
1484 spin_unlock(&ftrace_lock); 1478 spin_unlock(&ftrace_lock);
1485 1479
1486 return found ? 0 : -EINVAL; 1480 return found ? 0 : -EINVAL;