• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "ecmascript/compiler/aot_file/gdb_jit.h"
17 
18 #include <securec.h>
19 #include <mutex>
20 
21 #include "ecmascript/log_wrapper.h"
22 #include "libpandabase/macros.h"
23 #include "llvm/BinaryFormat/ELF.h"
24 
25 #ifndef PANDA_TARGET_MACOS
26 // Keep in sync with gdb/gdb/jit.h
27 extern "C" {
28 typedef enum {
29     JIT_NOACTION = 0,
30     JIT_REGISTER_FN,
31     JIT_UNREGISTER_FN
32 } jit_actions_t;
33 
34 struct jit_code_entry {
35     struct jit_code_entry *next_entry;
36     struct jit_code_entry *prev_entry;
37     const char *symfile_addr;
38     uint64_t symfile_size;
39     const char *file_addr; // extend the standard
40 };
41 
42 struct jit_descriptor {
43     uint32_t version;
44     // This should be jit_actions_t, but we want to be specific about the
45     // bit-width.
46     uint32_t action_flag;
47     struct jit_code_entry *relevant_entry;
48     struct jit_code_entry *first_entry;
49 };
50 
51 // We put information about the JITed function in this global, which the
52 // debugger reads.  Make sure to specify the version statically, because the
53 // debugger checks the version before we can set it during runtime.
54 struct jit_descriptor __jit_debug_descriptor = {
55     1, JIT_NOACTION, nullptr, nullptr
56 };
57 
58 // Debuggers puts a breakpoint in this function.
__jit_debug_register_code()59 void __attribute__((noinline)) __jit_debug_register_code()
60 {
61     LOG_COMPILER(INFO) << "__jit_debug_register_code() is called.";
62 }
63 }
64 
65 std::mutex g_descMutex;
66 
67 namespace panda::ecmascript {
68 namespace jit_debug {
69 using namespace llvm::ELF;
70 
71 static bool RegisterStubAnToDebuggerImpl(const char *fileAddr);
72 
RegisterStubAnToDebugger(const char * fileAddr)73 void RegisterStubAnToDebugger(const char *fileAddr)
74 {
75     std::lock_guard<std::mutex> guard(g_descMutex);
76     auto entry = __jit_debug_descriptor.first_entry;
77     while (entry != nullptr && entry->file_addr != fileAddr) {
78         entry = entry->next_entry;
79     }
80     if (entry != nullptr) {
81         return;
82     }
83     if (RegisterStubAnToDebuggerImpl(fileAddr)) {
84         LOG_COMPILER(INFO) << "success to register stub.an to debugger.";
85     } else {
86         LOG_COMPILER(ERROR) << "Can't register stub.an to debugger.";
87     }
88 }
89 
UnregisterStubAnFromDebugger(const char * fileAddr)90 void UnregisterStubAnFromDebugger(const char *fileAddr)
91 {
92     std::lock_guard<std::mutex> guard(g_descMutex);
93     auto entry = __jit_debug_descriptor.first_entry;
94     while (entry != nullptr && entry->file_addr != fileAddr) {
95         entry = entry->next_entry;
96     }
97     if (entry == nullptr) {
98         return;
99     }
100     if (entry->prev_entry != nullptr) {
101         entry->prev_entry->next_entry = entry->next_entry;
102     }
103     if (entry->next_entry != nullptr) {
104         entry->next_entry->prev_entry = entry->prev_entry;
105     }
106     __jit_debug_descriptor.action_flag = JIT_UNREGISTER_FN;
107     __jit_debug_descriptor.relevant_entry = entry;
108     __jit_debug_register_code();
109     __jit_debug_descriptor.relevant_entry = nullptr;
110     delete entry->symfile_addr;
111     delete entry;
112 }
113 
114 template<typename T, typename U>
OffsetAlignUp(U * addr,uint64_t offset,uint32_t align)115 inline T OffsetAlignUp(U *addr, uint64_t offset, uint32_t align)
116 {
117     auto value = reinterpret_cast<uint64_t>(addr) + offset;
118     auto result = value;
119     if (align != 0 && (value % align != 0)) {
120         result = value + (align - (value % align));
121     }
122     return reinterpret_cast<T>(result);
123 }
124 
125 struct StubAnInfo {
126     uintptr_t fileAddr;
127     Elf64_Ehdr *ehdr;
128     Elf64_Shdr *shdrTab;
129     uint32_t shStrIdx;
130     Elf64_Shdr *shStrHdr;
131     Elf64_Shdr *textHdr;
132     Elf64_Shdr *asmstubHdr;
133     Elf64_Shdr *symtabHdr;
134     Elf64_Shdr *strtabHdr;
135     uint64_t bcStubBegin;
136     uint64_t bcStubEnd;
137     uint32_t symCnt;
138 };
139 
140 /*
141  * [0] file header
142  * [1] program header
143  * [2] shstrtab
144  * [3] strtab
145  * [4] symtab
146  * [5] .eh_frame
147  * [6] empty header
148  * [7] shstrtab-header
149  * [8] strtab-header
150  * [9] symtab-header
151  * [10] text-header
152  * [11] .eh_frame header
153  */
154 const char SHSTR[] = "\0.shstrtab\0.strtab\0.symtab\0.text\0.eh_frame";
155 const uint32_t SHSTRTAB_NAME = 1;
156 const uint32_t STRTAB_NAME = SHSTRTAB_NAME + strlen(".shstrtab") + 1;
157 const uint32_t SYMTAB_NAME = STRTAB_NAME + strlen(".strtab") + 1;
158 const uint32_t TEXT_NAME = SYMTAB_NAME + strlen(".symtab") + 1;
159 const uint32_t EH_FRAME_NAME = TEXT_NAME + strlen(".text") + 1;
160 
161 const uint32_t SHSTRTAB_HDR_IDX = 1;
162 const uint32_t STRTAB_HDR_IDX = 2;
163 const uint32_t SYMTAB_HDR_IDX = 3;
164 const uint32_t TEXT_HDR_IDX = 4;
165 
166 const uint32_t HEADER_CNT = 6;
167 
InfoGetBind(unsigned char info)168 inline int InfoGetBind(unsigned char info)
169 {
170     const uint32_t shift = 4;
171     return info >> shift;
172 }
173 
CollectStubAnInfo(uintptr_t fileAddr)174 StubAnInfo CollectStubAnInfo(uintptr_t fileAddr)
175 {
176     auto *ehdr = reinterpret_cast<Elf64_Ehdr *>(fileAddr);
177     auto *shdrTab = reinterpret_cast<Elf64_Shdr *>(fileAddr + ehdr->e_shoff);
178     uint32_t shStrIdx = ehdr->e_shstrndx;
179     Elf64_Shdr *shStrHdr = &shdrTab[shStrIdx];
180     const char *shstrtab = reinterpret_cast<const char *>(fileAddr + shStrHdr->sh_offset);
181     Elf64_Shdr *textHdr = nullptr;
182     Elf64_Shdr *asmstubHdr = nullptr;
183     Elf64_Shdr *symtabHdr = nullptr;
184     Elf64_Shdr *strtabHdr = nullptr;
185     for (uint32_t i = 0; i < ehdr->e_shnum; i++) {
186         Elf64_Shdr *shdr = &shdrTab[i];
187         const char *name = &shstrtab[shdr->sh_name];
188         if (strcmp(name, ".text") == 0) {
189             textHdr = shdr;
190         } else if (strcmp(name, ".ark_asmstub") == 0) {
191             asmstubHdr = shdr;
192         } else if (strcmp(name, ".symtab") == 0) {
193             symtabHdr = shdr;
194         } else if (strcmp(name, ".strtab") == 0) {
195             strtabHdr = shdr;
196         }
197     }
198     ASSERT(symtabHdr != nullptr);
199     Elf64_Sym *symtab = reinterpret_cast<Elf64_Sym *>(fileAddr + symtabHdr->sh_offset);
200     const char *strtab = reinterpret_cast<const char *>(fileAddr + strtabHdr->sh_offset);
201     uint32_t symCnt = 2;
202     uint64_t bcStubBegin = UINT64_MAX;
203     uint64_t bcStubEnd = 0;
204     for (uint32_t symIdx = 0; symIdx < symtabHdr->sh_size / symtabHdr->sh_entsize; symIdx++) {
205         Elf64_Sym *sym = symtab + symIdx;
206         if (InfoGetBind(sym->st_info) != STB_GLOBAL) {
207             continue;
208         }
209         if (strncmp(&strtab[sym->st_name], "BCStub", strlen("BCStub")) != 0) {
210             symCnt++;
211         } else {
212             if (sym->st_value < bcStubBegin) {
213                 bcStubBegin = sym->st_value;
214             }
215             if (sym->st_value + sym->st_size > bcStubEnd) {
216                 bcStubEnd = sym->st_value + sym->st_size;
217             }
218         }
219     }
220     return StubAnInfo {
221         fileAddr, ehdr, shdrTab, shStrIdx, shStrHdr, textHdr, asmstubHdr, symtabHdr, strtabHdr,
222         bcStubBegin, bcStubEnd, symCnt
223     };
224 }
225 
CopyStrTab(uintptr_t baseAddr,const StubAnInfo & info)226 bool CopyStrTab(uintptr_t baseAddr, const StubAnInfo &info)
227 {
228     Elf64_Ehdr *newEhdr = reinterpret_cast<Elf64_Ehdr *>(baseAddr);
229     Elf64_Phdr *newPhdr = reinterpret_cast<Elf64_Phdr *>(newEhdr + 1);
230     char *shStrBuff = reinterpret_cast<char *>(newPhdr + 1);
231     if (memcpy_s(shStrBuff, sizeof(SHSTR), SHSTR, sizeof(SHSTR)) != EOK) {
232         return false;
233     }
234     char *newStrtab = shStrBuff + sizeof(SHSTR);
235     if (memcpy_s(newStrtab, info.strtabHdr->sh_size,
236         reinterpret_cast<void *>(info.fileAddr + info.strtabHdr->sh_offset), info.strtabHdr->sh_size) != EOK) {
237         return false;
238     }
239     const char bcStubName[] = "BCStubInterpreterRoutine";
240     if (memcpy_s((newStrtab + 1), sizeof(bcStubName), bcStubName, sizeof(bcStubName)) != EOK) {
241         return false;
242     }
243     return true;
244 }
245 
ConstructSymTab(Elf64_Sym * newSymtab,const StubAnInfo & info)246 void ConstructSymTab(Elf64_Sym *newSymtab, const StubAnInfo &info)
247 {
248     Elf64_Sym *symtab = reinterpret_cast<Elf64_Sym *>(info.fileAddr + info.symtabHdr->sh_offset);
249     const char *strtab = reinterpret_cast<const char *>(info.fileAddr + info.strtabHdr->sh_offset);
250     memset_s(newSymtab, sizeof(Elf64_Sym), 0, sizeof(Elf64_Sym));
251     uint32_t newSymIdx = 1;
252     for (uint32_t symIdx = 0; symIdx < info.symtabHdr->sh_size / info.symtabHdr->sh_entsize; symIdx++) {
253         Elf64_Sym *src = symtab + symIdx;
254         if (InfoGetBind(src->st_info) == STB_GLOBAL
255             && strncmp(&strtab[src->st_name], "BCStub", strlen("BCStub")) != 0) {
256             auto dst = newSymtab + newSymIdx;
257             newSymIdx++;
258             *dst = *src;
259             dst->st_shndx = TEXT_HDR_IDX;
260             dst->st_value -= info.textHdr->sh_offset;
261         }
262     }
263     auto bcSym = newSymtab + newSymIdx;
264     bcSym->st_name = 1;
265     bcSym->st_info = newSymtab[1].st_info;
266     bcSym->st_other = newSymtab[1].st_other;
267     bcSym->st_shndx = TEXT_HDR_IDX;
268     bcSym->st_value = info.bcStubBegin - info.textHdr->sh_offset;
269     ASSERT(info.bcStubEnd >= info.bcStubBegin);
270     bcSym->st_size = info.bcStubEnd - info.bcStubBegin;
271 }
272 
ConstructEhdrAndPhdr(Elf64_Ehdr * newEhdr,Elf64_Shdr * newShdrtab,uintptr_t baseAddr,const StubAnInfo & info)273 void ConstructEhdrAndPhdr(Elf64_Ehdr *newEhdr, Elf64_Shdr *newShdrtab, uintptr_t baseAddr, const StubAnInfo &info)
274 {
275     Elf64_Phdr *newPhdr = reinterpret_cast<Elf64_Phdr *>(newEhdr + 1);
276     {
277         *newEhdr = *info.ehdr;
278         newEhdr->e_flags = info.ehdr->e_flags;
279         newEhdr->e_machine = info.ehdr->e_machine;
280         if (memcpy_s(newEhdr->e_ident, sizeof(info.ehdr->e_ident),
281                      info.ehdr->e_ident, sizeof(info.ehdr->e_ident)) != EOK) {
282             return;
283         }
284         newEhdr->e_version = 1;
285         newEhdr->e_phoff = sizeof(Elf64_Ehdr);
286         newEhdr->e_shoff = reinterpret_cast<uintptr_t>(newShdrtab) - baseAddr;
287         newEhdr->e_ehsize = sizeof(Elf64_Ehdr);
288         newEhdr->e_phentsize = sizeof(Elf64_Phdr);
289         newEhdr->e_phnum = 1;
290         newEhdr->e_shentsize = sizeof(Elf64_Shdr);
291         newEhdr->e_shnum = HEADER_CNT;
292         newEhdr->e_shstrndx = SHSTRTAB_HDR_IDX;
293         newEhdr->e_type = ET_REL;
294         newEhdr->e_entry = 0;
295     }
296     uintptr_t textAddr = info.textHdr->sh_offset + info.fileAddr;
297     uint64_t textSize = info.asmstubHdr->sh_offset + info.asmstubHdr->sh_size - info.textHdr->sh_offset;
298     {
299         newPhdr->p_type = PT_LOAD;
300         newPhdr->p_flags = PF_X | PF_R;
301         newPhdr->p_offset = textAddr - info.fileAddr;
302         newPhdr->p_vaddr = textAddr;
303         newPhdr->p_paddr = textAddr;
304         newPhdr->p_filesz = textSize;
305         newPhdr->p_memsz = textSize;
306         newPhdr->p_align = 0x1000;
307     }
308 }
309 
ConstructShdrTab(Elf64_Shdr * newShdrTab,Elf64_Sym * newSymtab,uintptr_t baseAddr,void * ehFrame,uint32_t ehFrameSize,const StubAnInfo & info)310 void ConstructShdrTab(Elf64_Shdr *newShdrTab, Elf64_Sym *newSymtab, uintptr_t baseAddr, void *ehFrame,
311                       uint32_t ehFrameSize, const StubAnInfo &info)
312 {
313     Elf64_Shdr hdr{};
314     Elf64_Shdr *emptyShdr = newShdrTab;
315     Elf64_Shdr *newShstrHdr = emptyShdr + 1;
316     Elf64_Shdr *newStrtabHdr = newShstrHdr + 1;
317     Elf64_Shdr *newSymHdr = newStrtabHdr + 1;
318     Elf64_Shdr *newTextHdr = newSymHdr + 1;
319     Elf64_Shdr *ehFrameHdr = newTextHdr + 1;
320     *emptyShdr = hdr;
321 
322     newShstrHdr->sh_offset = sizeof(Elf64_Ehdr) + sizeof(Elf64_Phdr);
323     newShstrHdr->sh_size = sizeof(SHSTR);
324     newShstrHdr->sh_name = SHSTRTAB_NAME;
325     newShstrHdr->sh_addr = newStrtabHdr->sh_offset + baseAddr;
326     newShstrHdr->sh_type = SHT_STRTAB;
327     newShstrHdr->sh_flags = SHF_ALLOC;
328 
329     newStrtabHdr->sh_offset = newShstrHdr->sh_offset + newShstrHdr->sh_size;
330     newStrtabHdr->sh_size = info.strtabHdr->sh_size;
331     newStrtabHdr->sh_name = STRTAB_NAME;
332     newStrtabHdr->sh_addr = newStrtabHdr->sh_offset + baseAddr;
333     newStrtabHdr->sh_addralign = 1;
334     newStrtabHdr->sh_type = SHT_STRTAB;
335     newStrtabHdr->sh_flags = SHF_ALLOC;
336     newStrtabHdr->sh_link = SHSTRTAB_HDR_IDX;
337 
338     *newSymHdr = *info.symtabHdr;
339     newSymHdr->sh_offset = reinterpret_cast<uintptr_t>(newSymtab) - baseAddr;
340     newSymHdr->sh_size = info.symCnt * info.symtabHdr->sh_entsize;
341     newSymHdr->sh_entsize = info.symtabHdr->sh_entsize;
342     newSymHdr->sh_addralign = info.symtabHdr->sh_addralign;
343     newSymHdr->sh_name = SYMTAB_NAME;
344     newSymHdr->sh_addr = reinterpret_cast<uintptr_t>(newSymtab);
345     newSymHdr->sh_link = STRTAB_HDR_IDX;
346 
347     newTextHdr->sh_offset = 0;
348     newTextHdr->sh_size = info.asmstubHdr->sh_offset + info.asmstubHdr->sh_size - info.textHdr->sh_offset;
349     newTextHdr->sh_name = TEXT_NAME;
350     newTextHdr->sh_addr = info.fileAddr + info.textHdr->sh_offset;
351     newTextHdr->sh_addralign = sizeof(uint32_t);
352     newTextHdr->sh_type = SHT_NOBITS;
353     newTextHdr->sh_flags = SHF_ALLOC | SHF_EXECINSTR;
354     newTextHdr->sh_link = SYMTAB_HDR_IDX;
355 
356     ehFrameHdr->sh_offset = reinterpret_cast<uintptr_t>(ehFrame) - baseAddr;
357     ehFrameHdr->sh_size = ehFrameSize;
358     ehFrameHdr->sh_name = EH_FRAME_NAME;
359     ehFrameHdr->sh_addr = reinterpret_cast<uintptr_t>(ehFrame);
360     ehFrameHdr->sh_addralign = sizeof(uintptr_t);
361     ehFrameHdr->sh_type = SHT_PROGBITS;
362     ehFrameHdr->sh_flags = SHF_ALLOC;
363     ehFrameHdr->sh_link = TEXT_HDR_IDX;
364 }
365 
CreateDebuggerElf(uintptr_t fileAddr,void ** result,uint64_t * elfSize)366 bool CreateDebuggerElf(uintptr_t fileAddr, void **result, uint64_t *elfSize)
367 {
368     auto info = CollectStubAnInfo(fileAddr);
369     std::vector<uint8_t> ehFrame {
370             0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x4, 0x78, 0x1e, 0x0, 0x0, 0x0,
371             0x0, 0x0, 0x0, 0x0, 0x4b, 0x0, 0x0, 0x0, 0x18, 0x0, 0x0, 0x0, 0x0, 0xe0, 0x73, 0xab,
372             0xff, 0xff, 0x0, 0x0, 0x30, 0x2c, 0x12, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc, 0x1d, 0x0, 0x10,
373             0x1e, 0x17, 0x8d, 0x0, 0x12, 0x8, 0x18, 0x1c, 0x6, 0x8, 0x0, 0x29, 0x28, 0x7, 0x0, 0x8,
374             0x10, 0x1c, 0x6, 0x2f, 0xee, 0xff, 0x8, 0x8, 0x22, 0x10, 0x1d, 0x17, 0x8d, 0x0, 0x12, 0x8,
375             0x18, 0x1c, 0x6, 0x8, 0x0, 0x29, 0x28, 0x7, 0x0, 0x8, 0x10, 0x1c, 0x6, 0x2f, 0xee, 0xff,
376             0x8, 0x0, 0x22,
377     };
378     const uint32_t addrOff = 28;
379     const uint32_t lenOff = 36;
380     auto writeU64 = [&ehFrame](uint32_t idx, uint64_t data) {
381         for (uint32_t i = 0; i < sizeof(uint64_t); i++) {
382             ehFrame[idx + i] = (data >> (8 * i)) & 0xff;
383         }
384     };
385     writeU64(addrOff, info.bcStubBegin + fileAddr);
386     ASSERT(info.bcStubEnd >= info.bcStubBegin);
387     writeU64(lenOff, info.bcStubEnd - info.bcStubBegin);
388 
389     uint32_t totalSize = sizeof(Elf64_Ehdr) + sizeof(Elf64_Phdr) + sizeof(SHSTR) + info.strtabHdr->sh_size;
390     totalSize += info.symtabHdr->sh_entsize * info.symCnt + sizeof(Elf64_Sym); // for align
391     totalSize += ehFrame.size() + sizeof(uintptr_t);
392     totalSize += sizeof(Elf64_Shdr) * HEADER_CNT + sizeof(Elf64_Shdr); // for align
393 
394     char *buffer = new char[totalSize];
395     Elf64_Ehdr *newEhdr = reinterpret_cast<Elf64_Ehdr *>(buffer);
396     Elf64_Phdr *newPhdr = reinterpret_cast<Elf64_Phdr *>(newEhdr + 1);
397     const char *shStrBuff = reinterpret_cast<const char *>(newPhdr + 1);
398     const char *newStrtab = shStrBuff + sizeof(SHSTR);
399     if (!CopyStrTab(reinterpret_cast<uintptr_t>(buffer), info)) {
400         delete[] buffer;
401         return false;
402     }
403 
404     auto newSymtab = OffsetAlignUp<Elf64_Sym *>(newStrtab, info.strtabHdr->sh_size, info.symtabHdr->sh_addralign);
405     ConstructSymTab(newSymtab, info);
406 
407     auto ehFrameBuffer = OffsetAlignUp<char *>(newSymtab, info.symtabHdr->sh_entsize * info.symCnt, sizeof(uintptr_t));
408     if (memcpy_s(ehFrameBuffer, ehFrame.size(), ehFrame.data(), ehFrame.size()) != EOK) {
409         delete[] buffer;
410         return false;
411     }
412 
413     auto newShdrtab = OffsetAlignUp<Elf64_Shdr *>(ehFrameBuffer, ehFrame.size(), sizeof(uintptr_t));
414     ConstructEhdrAndPhdr(newEhdr, newShdrtab, reinterpret_cast<uintptr_t>(buffer), info);
415     ConstructShdrTab(newShdrtab, newSymtab, reinterpret_cast<uintptr_t>(buffer), ehFrameBuffer, ehFrame.size(), info);
416 
417     *result = reinterpret_cast<void *>(buffer);
418     *elfSize = totalSize;
419     return true;
420 }
421 
RegisterStubAnToDebuggerImpl(const char * fileAddr)422 static bool RegisterStubAnToDebuggerImpl(const char *fileAddr)
423 {
424     auto *entry = new jit_code_entry;
425     if (!CreateDebuggerElf(reinterpret_cast<uintptr_t>(fileAddr),
426         reinterpret_cast<void **>(const_cast<char **>(&entry->symfile_addr)), &entry->symfile_size)) {
427         delete entry;
428         return false;
429     }
430     entry->prev_entry = nullptr;
431     entry->file_addr = fileAddr;
432 
433     // Insert this entry at the head of the list.
434     jit_code_entry *nextEntry = __jit_debug_descriptor.first_entry;
435     entry->next_entry = nextEntry;
436     if (nextEntry) {
437         nextEntry->prev_entry = entry;
438     }
439 
440     __jit_debug_descriptor.first_entry = entry;
441     __jit_debug_descriptor.relevant_entry = entry;
442     __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
443     __jit_debug_register_code();
444     return true;
445 }
446 
447 }
448 }
449 #else
450 namespace panda::ecmascript {
451 namespace jit_debug {
RegisterStubAnToDebugger(const char * fileAddr)452 void RegisterStubAnToDebugger(const char *fileAddr)
453 {
454     LOG_COMPILER(INFO) << "MACOS doesn't support RegisterStubAnToDebugger, fileAddr is" << fileAddr;
455 }
456 
UnregisterStubAnFromDebugger(const char * fileAddr)457 void UnregisterStubAnFromDebugger(const char *fileAddr)
458 {
459     LOG_COMPILER(INFO) << "MACOS doesn't support RegisterStubAnToDebugger, fileAddr is" << fileAddr;
460 }
461 }
462 }
463 #endif
464