/ disassembler / Disassembler.cpp
Disassembler.cpp
1 /* 2 * Copyright (C) 2012-2018 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #include "config.h" 27 #include "Disassembler.h" 28 29 #include "MacroAssemblerCodeRef.h" 30 #include <wtf/Condition.h> 31 #include <wtf/DataLog.h> 32 #include <wtf/Deque.h> 33 #include <wtf/Lock.h> 34 #include <wtf/NeverDestroyed.h> 35 #include <wtf/Threading.h> 36 37 namespace JSC { 38 39 void disassemble(const MacroAssemblerCodePtr<DisassemblyPtrTag>& codePtr, size_t size, const char* prefix, PrintStream& out) 40 { 41 if (tryToDisassemble(codePtr, size, prefix, out)) 42 return; 43 44 out.printf("%sdisassembly not available for range %p...%p\n", prefix, codePtr.untaggedExecutableAddress(), codePtr.untaggedExecutableAddress<char*>() + size); 45 } 46 47 namespace { 48 49 // This is really a struct, except that it should be a class because that's what the WTF_* macros 50 // expect. 51 class DisassemblyTask { 52 WTF_MAKE_NONCOPYABLE(DisassemblyTask); 53 WTF_MAKE_FAST_ALLOCATED; 54 public: 55 DisassemblyTask() 56 { 57 } 58 59 ~DisassemblyTask() 60 { 61 if (header) 62 free(header); // free() because it would have been copied by strdup. 63 } 64 65 char* header { nullptr }; 66 MacroAssemblerCodeRef<DisassemblyPtrTag> codeRef; 67 size_t size { 0 }; 68 const char* prefix { nullptr }; 69 }; 70 71 class AsynchronousDisassembler { 72 public: 73 AsynchronousDisassembler() 74 { 75 Thread::create("Asynchronous Disassembler", [&] () { run(); }); 76 } 77 78 void enqueue(std::unique_ptr<DisassemblyTask> task) 79 { 80 LockHolder locker(m_lock); 81 m_queue.append(WTFMove(task)); 82 m_condition.notifyAll(); 83 } 84 85 void waitUntilEmpty() 86 { 87 LockHolder locker(m_lock); 88 while (!m_queue.isEmpty() || m_working) 89 m_condition.wait(m_lock); 90 } 91 92 private: 93 NO_RETURN void run() 94 { 95 for (;;) { 96 std::unique_ptr<DisassemblyTask> task; 97 { 98 LockHolder locker(m_lock); 99 m_working = false; 100 m_condition.notifyAll(); 101 while (m_queue.isEmpty()) 102 m_condition.wait(m_lock); 103 task = m_queue.takeFirst(); 104 m_working = true; 105 } 106 107 dataLog(task->header); 108 disassemble(task->codeRef.code(), task->size, task->prefix, WTF::dataFile()); 109 } 110 } 111 112 Lock m_lock; 113 Condition m_condition; 114 Deque<std::unique_ptr<DisassemblyTask>> m_queue; 115 bool m_working { false }; 116 }; 117 118 bool hadAnyAsynchronousDisassembly = false; 119 120 AsynchronousDisassembler& asynchronousDisassembler() 121 { 122 static LazyNeverDestroyed<AsynchronousDisassembler> disassembler; 123 static std::once_flag onceKey; 124 std::call_once(onceKey, [&] { 125 disassembler.construct(); 126 hadAnyAsynchronousDisassembly = true; 127 }); 128 return disassembler.get(); 129 } 130 131 } // anonymous namespace 132 133 void disassembleAsynchronously( 134 const CString& header, const MacroAssemblerCodeRef<DisassemblyPtrTag>& codeRef, size_t size, const char* prefix) 135 { 136 std::unique_ptr<DisassemblyTask> task = makeUnique<DisassemblyTask>(); 137 task->header = strdup(header.data()); // Yuck! We need this because CString does racy refcounting. 138 task->codeRef = codeRef; 139 task->size = size; 140 task->prefix = prefix; 141 142 asynchronousDisassembler().enqueue(WTFMove(task)); 143 } 144 145 void waitForAsynchronousDisassembly() 146 { 147 if (!hadAnyAsynchronousDisassembly) 148 return; 149 150 asynchronousDisassembler().waitUntilEmpty(); 151 } 152 153 } // namespace JSC 154