orc.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. #include <linux/objtool_types.h>
  3. #include <asm/orc_types.h>
  4. #include <objtool/check.h>
  5. #include <objtool/orc.h>
  6. #include <objtool/warn.h>
  7. int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi, struct instruction *insn)
  8. {
  9. struct cfi_reg *fp = &cfi->regs[CFI_FP];
  10. struct cfi_reg *ra = &cfi->regs[CFI_RA];
  11. memset(orc, 0, sizeof(*orc));
  12. if (!cfi) {
  13. /*
  14. * This is usually either unreachable nops/traps (which don't
  15. * trigger unreachable instruction warnings), or
  16. * STACK_FRAME_NON_STANDARD functions.
  17. */
  18. orc->type = ORC_TYPE_UNDEFINED;
  19. return 0;
  20. }
  21. switch (cfi->type) {
  22. case UNWIND_HINT_TYPE_UNDEFINED:
  23. orc->type = ORC_TYPE_UNDEFINED;
  24. return 0;
  25. case UNWIND_HINT_TYPE_END_OF_STACK:
  26. orc->type = ORC_TYPE_END_OF_STACK;
  27. return 0;
  28. case UNWIND_HINT_TYPE_CALL:
  29. orc->type = ORC_TYPE_CALL;
  30. break;
  31. case UNWIND_HINT_TYPE_REGS:
  32. orc->type = ORC_TYPE_REGS;
  33. break;
  34. case UNWIND_HINT_TYPE_REGS_PARTIAL:
  35. orc->type = ORC_TYPE_REGS_PARTIAL;
  36. break;
  37. default:
  38. ERROR_INSN(insn, "unknown unwind hint type %d", cfi->type);
  39. return -1;
  40. }
  41. orc->signal = cfi->signal;
  42. switch (cfi->cfa.base) {
  43. case CFI_SP:
  44. orc->sp_reg = ORC_REG_SP;
  45. break;
  46. case CFI_FP:
  47. orc->sp_reg = ORC_REG_FP;
  48. break;
  49. default:
  50. ERROR_INSN(insn, "unknown CFA base reg %d", cfi->cfa.base);
  51. return -1;
  52. }
  53. switch (fp->base) {
  54. case CFI_UNDEFINED:
  55. orc->fp_reg = ORC_REG_UNDEFINED;
  56. orc->fp_offset = 0;
  57. break;
  58. case CFI_CFA:
  59. orc->fp_reg = ORC_REG_PREV_SP;
  60. orc->fp_offset = fp->offset;
  61. break;
  62. case CFI_FP:
  63. orc->fp_reg = ORC_REG_FP;
  64. break;
  65. default:
  66. ERROR_INSN(insn, "unknown FP base reg %d", fp->base);
  67. return -1;
  68. }
  69. switch (ra->base) {
  70. case CFI_UNDEFINED:
  71. orc->ra_reg = ORC_REG_UNDEFINED;
  72. orc->ra_offset = 0;
  73. break;
  74. case CFI_CFA:
  75. orc->ra_reg = ORC_REG_PREV_SP;
  76. orc->ra_offset = ra->offset;
  77. break;
  78. case CFI_FP:
  79. orc->ra_reg = ORC_REG_FP;
  80. break;
  81. default:
  82. ERROR_INSN(insn, "unknown RA base reg %d", ra->base);
  83. return -1;
  84. }
  85. orc->sp_offset = cfi->cfa.offset;
  86. return 0;
  87. }
  88. int write_orc_entry(struct elf *elf, struct section *orc_sec,
  89. struct section *ip_sec, unsigned int idx,
  90. struct section *insn_sec, unsigned long insn_off,
  91. struct orc_entry *o)
  92. {
  93. struct orc_entry *orc;
  94. /* populate ORC data */
  95. orc = (struct orc_entry *)orc_sec->data->d_buf + idx;
  96. memcpy(orc, o, sizeof(*orc));
  97. /* populate reloc for ip */
  98. if (!elf_init_reloc_text_sym(elf, ip_sec, idx * sizeof(int), idx,
  99. insn_sec, insn_off))
  100. return -1;
  101. return 0;
  102. }
  103. static const char *reg_name(unsigned int reg)
  104. {
  105. switch (reg) {
  106. case ORC_REG_SP:
  107. return "sp";
  108. case ORC_REG_FP:
  109. return "fp";
  110. case ORC_REG_PREV_SP:
  111. return "prevsp";
  112. default:
  113. return "?";
  114. }
  115. }
  116. static const char *orc_type_name(unsigned int type)
  117. {
  118. switch (type) {
  119. case UNWIND_HINT_TYPE_CALL:
  120. return "call";
  121. case UNWIND_HINT_TYPE_REGS:
  122. return "regs";
  123. case UNWIND_HINT_TYPE_REGS_PARTIAL:
  124. return "regs (partial)";
  125. default:
  126. return "?";
  127. }
  128. }
  129. static void print_reg(unsigned int reg, int offset)
  130. {
  131. if (reg == ORC_REG_UNDEFINED)
  132. printf(" (und) ");
  133. else
  134. printf("%s + %3d", reg_name(reg), offset);
  135. }
  136. void orc_print_dump(struct elf *dummy_elf, struct orc_entry *orc, int i)
  137. {
  138. printf("type:%s", orc_type_name(orc[i].type));
  139. printf(" sp:");
  140. print_reg(orc[i].sp_reg, orc[i].sp_offset);
  141. printf(" fp:");
  142. print_reg(orc[i].fp_reg, orc[i].fp_offset);
  143. printf(" ra:");
  144. print_reg(orc[i].ra_reg, orc[i].ra_offset);
  145. printf(" signal:%d\n", orc[i].signal);
  146. }