summaryrefslogtreecommitdiff
path: root/lib/hwasan
diff options
context:
space:
mode:
authorPeter Collingbourne <peter@pcc.me.uk>2019-06-27 23:16:13 +0000
committerPeter Collingbourne <peter@pcc.me.uk>2019-06-27 23:16:13 +0000
commitde3285c6c57be31b1a67cc1e5fdbd485c6b373f6 (patch)
tree62413f6315b898a5e5d2314631eca0b728b711ae /lib/hwasan
parent86555a91ea4243290620d034e0c200daba8de46f (diff)
downloadcompiler-rt-de3285c6c57be31b1a67cc1e5fdbd485c6b373f6.tar.gz
hwasan: Teach the runtime to identify the local variable being accessed in UAR reports.
Each function's PC is recorded in the ring buffer. From there we can access the function's local variables and reconstruct the tag of each one with the help of the information printed by llvm-symbolizer's new FRAME command. We can then find the variable that was likely being accessed by matching the pointer's tag against the reconstructed tag. Differential Revision: https://reviews.llvm.org/D63469 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@364607 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/hwasan')
-rw-r--r--lib/hwasan/hwasan.cpp36
-rw-r--r--lib/hwasan/hwasan.h8
-rw-r--r--lib/hwasan/hwasan_report.cpp94
3 files changed, 78 insertions, 60 deletions
diff --git a/lib/hwasan/hwasan.cpp b/lib/hwasan/hwasan.cpp
index fab680424..6f2246552 100644
--- a/lib/hwasan/hwasan.cpp
+++ b/lib/hwasan/hwasan.cpp
@@ -193,36 +193,6 @@ void UpdateMemoryUsage() {
void UpdateMemoryUsage() {}
#endif
-struct FrameDescription {
- uptr PC;
- const char *Descr;
-};
-
-struct FrameDescriptionArray {
- FrameDescription *beg, *end;
-};
-
-static InternalMmapVectorNoCtor<FrameDescriptionArray> AllFrames;
-
-void InitFrameDescriptors(uptr b, uptr e) {
- FrameDescription *beg = reinterpret_cast<FrameDescription *>(b);
- FrameDescription *end = reinterpret_cast<FrameDescription *>(e);
- if (beg == end)
- return;
- AllFrames.push_back({beg, end});
- if (Verbosity())
- for (FrameDescription *frame_descr = beg; frame_descr < end; frame_descr++)
- Printf("Frame: %p %s\n", frame_descr->PC, frame_descr->Descr);
-}
-
-const char *GetStackFrameDescr(uptr pc) {
- for (uptr i = 0, n = AllFrames.size(); i < n; i++)
- for (auto p = AllFrames[i].beg; p < AllFrames[i].end; p++)
- if (p->PC == pc)
- return p->Descr;
- return nullptr;
-}
-
// Prepare to run instrumented code on the main thread.
void InitInstrumentation() {
if (hwasan_instrumentation_inited) return;
@@ -267,9 +237,9 @@ using namespace __hwasan;
uptr __hwasan_shadow_memory_dynamic_address; // Global interface symbol.
-void __hwasan_init_frames(uptr beg, uptr end) {
- InitFrameDescriptors(beg, end);
-}
+// This function was used by the old frame descriptor mechanism. We keep it
+// around to avoid breaking ABI.
+void __hwasan_init_frames(uptr beg, uptr end) {}
void __hwasan_init_static() {
InitShadowGOT();
diff --git a/lib/hwasan/hwasan.h b/lib/hwasan/hwasan.h
index 9cc9490a9..465e56c3a 100644
--- a/lib/hwasan/hwasan.h
+++ b/lib/hwasan/hwasan.h
@@ -44,6 +44,11 @@ const uptr kAddressTagMask = 0xFFUL << kAddressTagShift;
// for threads and stack histories. This is an ABI constant.
const unsigned kShadowBaseAlignment = 32;
+const unsigned kRecordAddrBaseTagShift = 3;
+const unsigned kRecordFPShift = 48;
+const unsigned kRecordFPLShift = 4;
+const unsigned kRecordFPModulus = 1 << (64 - kRecordFPShift + kRecordFPLShift);
+
static inline tag_t GetTagFromPointer(uptr p) {
return p >> kAddressTagShift;
}
@@ -93,9 +98,6 @@ void hwasan_free(void *ptr, StackTrace *stack);
void InstallTrapHandler();
void InstallAtExitHandler();
-const char *GetStackOriginDescr(u32 id, uptr *pc);
-const char *GetStackFrameDescr(uptr pc);
-
void EnterSymbolizer();
void ExitSymbolizer();
bool IsInSymbolizer();
diff --git a/lib/hwasan/hwasan_report.cpp b/lib/hwasan/hwasan_report.cpp
index fa2fff742..a57a97174 100644
--- a/lib/hwasan/hwasan_report.cpp
+++ b/lib/hwasan/hwasan_report.cpp
@@ -139,6 +139,75 @@ uptr FindHeapAllocation(HeapAllocationsRingBuffer *rb,
return 0;
}
+static void PrintStackAllocations(StackAllocationsRingBuffer *sa,
+ tag_t addr_tag, uptr untagged_addr) {
+ uptr frames = Min((uptr)flags()->stack_history_size, sa->size());
+ bool found_local = false;
+ for (uptr i = 0; i < frames; i++) {
+ const uptr *record_addr = &(*sa)[i];
+ uptr record = *record_addr;
+ if (!record)
+ break;
+ tag_t base_tag =
+ reinterpret_cast<uptr>(record_addr) >> kRecordAddrBaseTagShift;
+ uptr fp = (record >> kRecordFPShift) << kRecordFPLShift;
+ uptr pc_mask = (1ULL << kRecordFPShift) - 1;
+ uptr pc = record & pc_mask;
+ FrameInfo frame;
+ if (Symbolizer::GetOrInit()->SymbolizeFrame(pc, &frame)) {
+ for (LocalInfo &local : frame.locals) {
+ if (!local.has_frame_offset || !local.has_size || !local.has_tag_offset)
+ continue;
+ tag_t obj_tag = base_tag ^ local.tag_offset;
+ if (obj_tag != addr_tag)
+ continue;
+ // Calculate the offset from the object address to the faulting
+ // address. Because we only store bits 4-19 of FP (bits 0-3 are
+ // guaranteed to be zero), the calculation is performed mod 2^20 and may
+ // harmlessly underflow if the address mod 2^20 is below the object
+ // address.
+ uptr obj_offset =
+ (untagged_addr - fp - local.frame_offset) & (kRecordFPModulus - 1);
+ if (obj_offset >= local.size)
+ continue;
+ if (!found_local) {
+ Printf("Potentially referenced stack objects:\n");
+ found_local = true;
+ }
+ Printf(" %s in %s %s:%d\n", local.name, local.function_name,
+ local.decl_file, local.decl_line);
+ }
+ frame.Clear();
+ }
+ }
+
+ if (found_local)
+ return;
+
+ // We didn't find any locals. Most likely we don't have symbols, so dump
+ // the information that we have for offline analysis.
+ InternalScopedString frame_desc(GetPageSizeCached() * 2);
+ Printf("Previously allocated frames:\n");
+ for (uptr i = 0; i < frames; i++) {
+ const uptr *record_addr = &(*sa)[i];
+ uptr record = *record_addr;
+ if (!record)
+ break;
+ uptr pc_mask = (1ULL << 48) - 1;
+ uptr pc = record & pc_mask;
+ frame_desc.append(" record_addr:0x%zx record:0x%zx",
+ reinterpret_cast<uptr>(record_addr), record);
+ if (SymbolizedStack *frame = Symbolizer::GetOrInit()->SymbolizePC(pc)) {
+ RenderFrame(&frame_desc, " %F %L\n", 0, frame->info,
+ common_flags()->symbolize_vs_style,
+ common_flags()->strip_path_prefix);
+ frame->ClearAll();
+ }
+ Printf("%s", frame_desc.data());
+ frame_desc.clear();
+ }
+}
+
void PrintAddressDescription(
uptr tagged_addr, uptr access_size,
StackAllocationsRingBuffer *current_stack_allocations) {
@@ -238,33 +307,10 @@ void PrintAddressDescription(
Printf("%s", d.Default());
t->Announce();
- // Temporary report section, needs to be improved.
- Printf("Previously allocated frames:\n");
auto *sa = (t == GetCurrentThread() && current_stack_allocations)
? current_stack_allocations
: t->stack_allocations();
- uptr frames = Min((uptr)flags()->stack_history_size, sa->size());
- InternalScopedString frame_desc(GetPageSizeCached() * 2);
- for (uptr i = 0; i < frames; i++) {
- uptr record = (*sa)[i];
- if (!record)
- break;
- uptr sp = (record >> 48) << 4;
- uptr pc_mask = (1ULL << 48) - 1;
- uptr pc = record & pc_mask;
- if (SymbolizedStack *frame = Symbolizer::GetOrInit()->SymbolizePC(pc)) {
- frame_desc.append(" sp: 0x%zx ", sp);
- RenderFrame(&frame_desc, "#%n %p %F %L\n", 0, frame->info,
- common_flags()->symbolize_vs_style,
- common_flags()->strip_path_prefix);
- frame->ClearAll();
- if (auto Descr = GetStackFrameDescr(pc))
- frame_desc.append(" %s\n", Descr);
- }
- Printf("%s", frame_desc.data());
- frame_desc.clear();
- }
-
+ PrintStackAllocations(sa, addr_tag, untagged_addr);
num_descriptions_printed++;
}
});