aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Rostedt <rostedt@goodmis.org>2008-10-01 10:52:51 -0400
committerIngo Molnar <mingo@elte.hu>2008-10-14 04:39:07 -0400
commit7104f300c5a69b46dda00d898034dd05c9f21739 (patch)
treea8c885bd61fb1e269f277837b2e521179faf8739
parent797d3712a9dd75c720558612be05f42c031a7bb5 (diff)
ftrace: type cast filter+verifier
The mmiotrace map had a bug that would typecast the entry from the trace to the wrong type. That is a known danger of C typecasts, there's absolutely zero checking done on them. Help that problem a bit by using a GCC extension to implement a type filter that restricts the types that a trace record can be cast into, and by adding a dynamic check (in debug mode) to verify the type of the entry. This patch adds a macro to assign all entries of ftrace using the type of the variable and checking the entry id. The typecasts are now done in the macro for only those types that it knows about, which should be all the types that are allowed to be read from the tracer. Signed-off-by: Steven Rostedt <srostedt@redhat.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r--kernel/trace/trace.c85
-rw-r--r--kernel/trace/trace.h42
-rw-r--r--kernel/trace/trace_mmiotrace.c14
3 files changed, 112 insertions, 29 deletions
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index c1634068adfa..948f7d821c62 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -1350,7 +1350,9 @@ print_lat_fmt(struct trace_iterator *iter, unsigned int trace_idx, int cpu)
1350 } 1350 }
1351 switch (entry->type) { 1351 switch (entry->type) {
1352 case TRACE_FN: { 1352 case TRACE_FN: {
1353 struct ftrace_entry *field = (struct ftrace_entry *)entry; 1353 struct ftrace_entry *field;
1354
1355 trace_assign_type(field, entry);
1354 1356
1355 seq_print_ip_sym(s, field->ip, sym_flags); 1357 seq_print_ip_sym(s, field->ip, sym_flags);
1356 trace_seq_puts(s, " ("); 1358 trace_seq_puts(s, " (");
@@ -1363,8 +1365,9 @@ print_lat_fmt(struct trace_iterator *iter, unsigned int trace_idx, int cpu)
1363 } 1365 }
1364 case TRACE_CTX: 1366 case TRACE_CTX:
1365 case TRACE_WAKE: { 1367 case TRACE_WAKE: {
1366 struct ctx_switch_entry *field = 1368 struct ctx_switch_entry *field;
1367 (struct ctx_switch_entry *)entry; 1369
1370 trace_assign_type(field, entry);
1368 1371
1369 T = field->next_state < sizeof(state_to_char) ? 1372 T = field->next_state < sizeof(state_to_char) ?
1370 state_to_char[field->next_state] : 'X'; 1373 state_to_char[field->next_state] : 'X';
@@ -1384,7 +1387,9 @@ print_lat_fmt(struct trace_iterator *iter, unsigned int trace_idx, int cpu)
1384 break; 1387 break;
1385 } 1388 }
1386 case TRACE_SPECIAL: { 1389 case TRACE_SPECIAL: {
1387 struct special_entry *field = (struct special_entry *)entry; 1390 struct special_entry *field;
1391
1392 trace_assign_type(field, entry);
1388 1393
1389 trace_seq_printf(s, "# %ld %ld %ld\n", 1394 trace_seq_printf(s, "# %ld %ld %ld\n",
1390 field->arg1, 1395 field->arg1,
@@ -1393,7 +1398,9 @@ print_lat_fmt(struct trace_iterator *iter, unsigned int trace_idx, int cpu)
1393 break; 1398 break;
1394 } 1399 }
1395 case TRACE_STACK: { 1400 case TRACE_STACK: {
1396 struct stack_entry *field = (struct stack_entry *)entry; 1401 struct stack_entry *field;
1402
1403 trace_assign_type(field, entry);
1397 1404
1398 for (i = 0; i < FTRACE_STACK_ENTRIES; i++) { 1405 for (i = 0; i < FTRACE_STACK_ENTRIES; i++) {
1399 if (i) 1406 if (i)
@@ -1404,7 +1411,9 @@ print_lat_fmt(struct trace_iterator *iter, unsigned int trace_idx, int cpu)
1404 break; 1411 break;
1405 } 1412 }
1406 case TRACE_PRINT: { 1413 case TRACE_PRINT: {
1407 struct print_entry *field = (struct print_entry *)entry; 1414 struct print_entry *field;
1415
1416 trace_assign_type(field, entry);
1408 1417
1409 seq_print_ip_sym(s, field->ip, sym_flags); 1418 seq_print_ip_sym(s, field->ip, sym_flags);
1410 trace_seq_printf(s, ": %s", field->buf); 1419 trace_seq_printf(s, ": %s", field->buf);
@@ -1454,7 +1463,9 @@ static enum print_line_t print_trace_fmt(struct trace_iterator *iter)
1454 1463
1455 switch (entry->type) { 1464 switch (entry->type) {
1456 case TRACE_FN: { 1465 case TRACE_FN: {
1457 struct ftrace_entry *field = (struct ftrace_entry *)entry; 1466 struct ftrace_entry *field;
1467
1468 trace_assign_type(field, entry);
1458 1469
1459 ret = seq_print_ip_sym(s, field->ip, sym_flags); 1470 ret = seq_print_ip_sym(s, field->ip, sym_flags);
1460 if (!ret) 1471 if (!ret)
@@ -1480,8 +1491,9 @@ static enum print_line_t print_trace_fmt(struct trace_iterator *iter)
1480 } 1491 }
1481 case TRACE_CTX: 1492 case TRACE_CTX:
1482 case TRACE_WAKE: { 1493 case TRACE_WAKE: {
1483 struct ctx_switch_entry *field = 1494 struct ctx_switch_entry *field;
1484 (struct ctx_switch_entry *)entry; 1495
1496 trace_assign_type(field, entry);
1485 1497
1486 S = field->prev_state < sizeof(state_to_char) ? 1498 S = field->prev_state < sizeof(state_to_char) ?
1487 state_to_char[field->prev_state] : 'X'; 1499 state_to_char[field->prev_state] : 'X';
@@ -1501,7 +1513,9 @@ static enum print_line_t print_trace_fmt(struct trace_iterator *iter)
1501 break; 1513 break;
1502 } 1514 }
1503 case TRACE_SPECIAL: { 1515 case TRACE_SPECIAL: {
1504 struct special_entry *field = (struct special_entry *)entry; 1516 struct special_entry *field;
1517
1518 trace_assign_type(field, entry);
1505 1519
1506 ret = trace_seq_printf(s, "# %ld %ld %ld\n", 1520 ret = trace_seq_printf(s, "# %ld %ld %ld\n",
1507 field->arg1, 1521 field->arg1,
@@ -1512,7 +1526,9 @@ static enum print_line_t print_trace_fmt(struct trace_iterator *iter)
1512 break; 1526 break;
1513 } 1527 }
1514 case TRACE_STACK: { 1528 case TRACE_STACK: {
1515 struct stack_entry *field = (struct stack_entry *)entry; 1529 struct stack_entry *field;
1530
1531 trace_assign_type(field, entry);
1516 1532
1517 for (i = 0; i < FTRACE_STACK_ENTRIES; i++) { 1533 for (i = 0; i < FTRACE_STACK_ENTRIES; i++) {
1518 if (i) { 1534 if (i) {
@@ -1531,7 +1547,9 @@ static enum print_line_t print_trace_fmt(struct trace_iterator *iter)
1531 break; 1547 break;
1532 } 1548 }
1533 case TRACE_PRINT: { 1549 case TRACE_PRINT: {
1534 struct print_entry *field = (struct print_entry *)entry; 1550 struct print_entry *field;
1551
1552 trace_assign_type(field, entry);
1535 1553
1536 seq_print_ip_sym(s, field->ip, sym_flags); 1554 seq_print_ip_sym(s, field->ip, sym_flags);
1537 trace_seq_printf(s, ": %s", field->buf); 1555 trace_seq_printf(s, ": %s", field->buf);
@@ -1562,7 +1580,9 @@ static enum print_line_t print_raw_fmt(struct trace_iterator *iter)
1562 1580
1563 switch (entry->type) { 1581 switch (entry->type) {
1564 case TRACE_FN: { 1582 case TRACE_FN: {
1565 struct ftrace_entry *field = (struct ftrace_entry *)entry; 1583 struct ftrace_entry *field;
1584
1585 trace_assign_type(field, entry);
1566 1586
1567 ret = trace_seq_printf(s, "%x %x\n", 1587 ret = trace_seq_printf(s, "%x %x\n",
1568 field->ip, 1588 field->ip,
@@ -1573,8 +1593,9 @@ static enum print_line_t print_raw_fmt(struct trace_iterator *iter)
1573 } 1593 }
1574 case TRACE_CTX: 1594 case TRACE_CTX:
1575 case TRACE_WAKE: { 1595 case TRACE_WAKE: {
1576 struct ctx_switch_entry *field = 1596 struct ctx_switch_entry *field;
1577 (struct ctx_switch_entry *)entry; 1597
1598 trace_assign_type(field, entry);
1578 1599
1579 S = field->prev_state < sizeof(state_to_char) ? 1600 S = field->prev_state < sizeof(state_to_char) ?
1580 state_to_char[field->prev_state] : 'X'; 1601 state_to_char[field->prev_state] : 'X';
@@ -1596,7 +1617,9 @@ static enum print_line_t print_raw_fmt(struct trace_iterator *iter)
1596 } 1617 }
1597 case TRACE_SPECIAL: 1618 case TRACE_SPECIAL:
1598 case TRACE_STACK: { 1619 case TRACE_STACK: {
1599 struct special_entry *field = (struct special_entry *)entry; 1620 struct special_entry *field;
1621
1622 trace_assign_type(field, entry);
1600 1623
1601 ret = trace_seq_printf(s, "# %ld %ld %ld\n", 1624 ret = trace_seq_printf(s, "# %ld %ld %ld\n",
1602 field->arg1, 1625 field->arg1,
@@ -1607,7 +1630,9 @@ static enum print_line_t print_raw_fmt(struct trace_iterator *iter)
1607 break; 1630 break;
1608 } 1631 }
1609 case TRACE_PRINT: { 1632 case TRACE_PRINT: {
1610 struct print_entry *field = (struct print_entry *)entry; 1633 struct print_entry *field;
1634
1635 trace_assign_type(field, entry);
1611 1636
1612 trace_seq_printf(s, "# %lx %s", field->ip, field->buf); 1637 trace_seq_printf(s, "# %lx %s", field->ip, field->buf);
1613 if (entry->flags & TRACE_FLAG_CONT) 1638 if (entry->flags & TRACE_FLAG_CONT)
@@ -1648,7 +1673,9 @@ static enum print_line_t print_hex_fmt(struct trace_iterator *iter)
1648 1673
1649 switch (entry->type) { 1674 switch (entry->type) {
1650 case TRACE_FN: { 1675 case TRACE_FN: {
1651 struct ftrace_entry *field = (struct ftrace_entry *)entry; 1676 struct ftrace_entry *field;
1677
1678 trace_assign_type(field, entry);
1652 1679
1653 SEQ_PUT_HEX_FIELD_RET(s, field->ip); 1680 SEQ_PUT_HEX_FIELD_RET(s, field->ip);
1654 SEQ_PUT_HEX_FIELD_RET(s, field->parent_ip); 1681 SEQ_PUT_HEX_FIELD_RET(s, field->parent_ip);
@@ -1656,8 +1683,9 @@ static enum print_line_t print_hex_fmt(struct trace_iterator *iter)
1656 } 1683 }
1657 case TRACE_CTX: 1684 case TRACE_CTX:
1658 case TRACE_WAKE: { 1685 case TRACE_WAKE: {
1659 struct ctx_switch_entry *field = 1686 struct ctx_switch_entry *field;
1660 (struct ctx_switch_entry *)entry; 1687
1688 trace_assign_type(field, entry);
1661 1689
1662 S = field->prev_state < sizeof(state_to_char) ? 1690 S = field->prev_state < sizeof(state_to_char) ?
1663 state_to_char[field->prev_state] : 'X'; 1691 state_to_char[field->prev_state] : 'X';
@@ -1676,7 +1704,9 @@ static enum print_line_t print_hex_fmt(struct trace_iterator *iter)
1676 } 1704 }
1677 case TRACE_SPECIAL: 1705 case TRACE_SPECIAL:
1678 case TRACE_STACK: { 1706 case TRACE_STACK: {
1679 struct special_entry *field = (struct special_entry *)entry; 1707 struct special_entry *field;
1708
1709 trace_assign_type(field, entry);
1680 1710
1681 SEQ_PUT_HEX_FIELD_RET(s, field->arg1); 1711 SEQ_PUT_HEX_FIELD_RET(s, field->arg1);
1682 SEQ_PUT_HEX_FIELD_RET(s, field->arg2); 1712 SEQ_PUT_HEX_FIELD_RET(s, field->arg2);
@@ -1705,15 +1735,18 @@ static enum print_line_t print_bin_fmt(struct trace_iterator *iter)
1705 1735
1706 switch (entry->type) { 1736 switch (entry->type) {
1707 case TRACE_FN: { 1737 case TRACE_FN: {
1708 struct ftrace_entry *field = (struct ftrace_entry *)entry; 1738 struct ftrace_entry *field;
1739
1740 trace_assign_type(field, entry);
1709 1741
1710 SEQ_PUT_FIELD_RET(s, field->ip); 1742 SEQ_PUT_FIELD_RET(s, field->ip);
1711 SEQ_PUT_FIELD_RET(s, field->parent_ip); 1743 SEQ_PUT_FIELD_RET(s, field->parent_ip);
1712 break; 1744 break;
1713 } 1745 }
1714 case TRACE_CTX: { 1746 case TRACE_CTX: {
1715 struct ctx_switch_entry *field = 1747 struct ctx_switch_entry *field;
1716 (struct ctx_switch_entry *)entry; 1748
1749 trace_assign_type(field, entry);
1717 1750
1718 SEQ_PUT_FIELD_RET(s, field->prev_pid); 1751 SEQ_PUT_FIELD_RET(s, field->prev_pid);
1719 SEQ_PUT_FIELD_RET(s, field->prev_prio); 1752 SEQ_PUT_FIELD_RET(s, field->prev_prio);
@@ -1725,7 +1758,9 @@ static enum print_line_t print_bin_fmt(struct trace_iterator *iter)
1725 } 1758 }
1726 case TRACE_SPECIAL: 1759 case TRACE_SPECIAL:
1727 case TRACE_STACK: { 1760 case TRACE_STACK: {
1728 struct special_entry *field = (struct special_entry *)entry; 1761 struct special_entry *field;
1762
1763 trace_assign_type(field, entry);
1729 1764
1730 SEQ_PUT_FIELD_RET(s, field->arg1); 1765 SEQ_PUT_FIELD_RET(s, field->arg1);
1731 SEQ_PUT_FIELD_RET(s, field->arg2); 1766 SEQ_PUT_FIELD_RET(s, field->arg2);
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index a921ba5d292d..f02042d0d828 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -177,6 +177,48 @@ struct trace_array {
177 struct trace_array_cpu *data[NR_CPUS]; 177 struct trace_array_cpu *data[NR_CPUS];
178}; 178};
179 179
180#define FTRACE_CMP_TYPE(var, type) \
181 __builtin_types_compatible_p(typeof(var), type *)
182
183#undef IF_ASSIGN
184#define IF_ASSIGN(var, entry, etype, id) \
185 if (FTRACE_CMP_TYPE(var, etype)) { \
186 var = (typeof(var))(entry); \
187 WARN_ON(id && (entry)->type != id); \
188 break; \
189 }
190
191/* Will cause compile errors if type is not found. */
192extern void __ftrace_bad_type(void);
193
194/*
195 * The trace_assign_type is a verifier that the entry type is
196 * the same as the type being assigned. To add new types simply
197 * add a line with the following format:
198 *
199 * IF_ASSIGN(var, ent, type, id);
200 *
201 * Where "type" is the trace type that includes the trace_entry
202 * as the "ent" item. And "id" is the trace identifier that is
203 * used in the trace_type enum.
204 *
205 * If the type can have more than one id, then use zero.
206 */
207#define trace_assign_type(var, ent) \
208 do { \
209 IF_ASSIGN(var, ent, struct ftrace_entry, TRACE_FN); \
210 IF_ASSIGN(var, ent, struct ctx_switch_entry, 0); \
211 IF_ASSIGN(var, ent, struct trace_field_cont, TRACE_CONT); \
212 IF_ASSIGN(var, ent, struct stack_entry, TRACE_STACK); \
213 IF_ASSIGN(var, ent, struct print_entry, TRACE_PRINT); \
214 IF_ASSIGN(var, ent, struct special_entry, 0); \
215 IF_ASSIGN(var, ent, struct trace_mmiotrace_rw, \
216 TRACE_MMIO_RW); \
217 IF_ASSIGN(var, ent, struct trace_mmiotrace_map, \
218 TRACE_MMIO_MAP); \
219 IF_ASSIGN(var, ent, struct trace_boot, TRACE_BOOT); \
220 __ftrace_bad_type(); \
221 } while (0)
180 222
181/* Return values for print_line callback */ 223/* Return values for print_line callback */
182enum print_line_t { 224enum print_line_t {
diff --git a/kernel/trace/trace_mmiotrace.c b/kernel/trace/trace_mmiotrace.c
index 1a266aa08e1a..0e819f47bb7a 100644
--- a/kernel/trace/trace_mmiotrace.c
+++ b/kernel/trace/trace_mmiotrace.c
@@ -178,15 +178,17 @@ print_out:
178static enum print_line_t mmio_print_rw(struct trace_iterator *iter) 178static enum print_line_t mmio_print_rw(struct trace_iterator *iter)
179{ 179{
180 struct trace_entry *entry = iter->ent; 180 struct trace_entry *entry = iter->ent;
181 struct trace_mmiotrace_rw *field = 181 struct trace_mmiotrace_rw *field;
182 (struct trace_mmiotrace_rw *)entry; 182 struct mmiotrace_rw *rw;
183 struct mmiotrace_rw *rw = &field->rw;
184 struct trace_seq *s = &iter->seq; 183 struct trace_seq *s = &iter->seq;
185 unsigned long long t = ns2usecs(iter->ts); 184 unsigned long long t = ns2usecs(iter->ts);
186 unsigned long usec_rem = do_div(t, 1000000ULL); 185 unsigned long usec_rem = do_div(t, 1000000ULL);
187 unsigned secs = (unsigned long)t; 186 unsigned secs = (unsigned long)t;
188 int ret = 1; 187 int ret = 1;
189 188
189 trace_assign_type(field, entry);
190 rw = &field->rw;
191
190 switch (rw->opcode) { 192 switch (rw->opcode) {
191 case MMIO_READ: 193 case MMIO_READ:
192 ret = trace_seq_printf(s, 194 ret = trace_seq_printf(s,
@@ -222,13 +224,17 @@ static enum print_line_t mmio_print_rw(struct trace_iterator *iter)
222static enum print_line_t mmio_print_map(struct trace_iterator *iter) 224static enum print_line_t mmio_print_map(struct trace_iterator *iter)
223{ 225{
224 struct trace_entry *entry = iter->ent; 226 struct trace_entry *entry = iter->ent;
225 struct mmiotrace_map *m = (struct mmiotrace_map *)entry; 227 struct trace_mmiotrace_map *field;
228 struct mmiotrace_map *m;
226 struct trace_seq *s = &iter->seq; 229 struct trace_seq *s = &iter->seq;
227 unsigned long long t = ns2usecs(iter->ts); 230 unsigned long long t = ns2usecs(iter->ts);
228 unsigned long usec_rem = do_div(t, 1000000ULL); 231 unsigned long usec_rem = do_div(t, 1000000ULL);
229 unsigned secs = (unsigned long)t; 232 unsigned secs = (unsigned long)t;
230 int ret; 233 int ret;
231 234
235 trace_assign_type(field, entry);
236 m = &field->map;
237
232 switch (m->opcode) { 238 switch (m->opcode) {
233 case MMIO_PROBE: 239 case MMIO_PROBE:
234 ret = trace_seq_printf(s, 240 ret = trace_seq_printf(s,