1 //===-- InferiorCallPOSIX.cpp -----------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "InferiorCallPOSIX.h"
11 #include "lldb/Core/StreamFile.h"
12 #include "lldb/Core/ValueObject.h"
13 #include "lldb/Symbol/SymbolContext.h"
14 #include "lldb/Target/ExecutionContext.h"
15 #include "lldb/Target/Process.h"
16 #include "lldb/Target/Target.h"
17 #include "lldb/Target/ThreadPlanCallFunction.h"
18 
19 #include <sys/mman.h>
20 
21 using namespace lldb;
22 using namespace lldb_private;
23 
24 bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr,
25                                     addr_t addr, addr_t length, unsigned prot,
26                                     unsigned flags, addr_t fd, addr_t offset) {
27     Thread *thread = process->GetThreadList().GetSelectedThread().get();
28     if (thread == NULL)
29         return false;
30 
31     const bool append = true;
32     const bool include_symbols = true;
33     const bool include_inlines = false;
34     SymbolContextList sc_list;
35     const uint32_t count
36       = process->GetTarget().GetImages().FindFunctions (ConstString ("mmap"),
37                                                         eFunctionNameTypeFull,
38                                                         include_symbols,
39                                                         include_inlines,
40                                                         append,
41                                                         sc_list);
42     if (count > 0)
43     {
44         SymbolContext sc;
45         if (sc_list.GetContextAtIndex(0, sc))
46         {
47             const uint32_t range_scope = eSymbolContextFunction | eSymbolContextSymbol;
48             const bool use_inline_block_range = false;
49             const bool stop_other_threads = true;
50             const bool discard_on_error = true;
51             const bool try_all_threads = true;
52             const uint32_t single_thread_timeout_usec = 500000;
53 
54             addr_t prot_arg, flags_arg = 0;
55             if (prot == eMmapProtNone)
56               prot_arg = PROT_NONE;
57             else {
58               prot_arg = 0;
59               if (prot & eMmapProtExec)
60                 prot_arg |= PROT_EXEC;
61               if (prot & eMmapProtRead)
62                 prot_arg |= PROT_READ;
63               if (prot & eMmapProtWrite)
64                 prot_arg |= PROT_WRITE;
65             }
66 
67             if (flags & eMmapFlagsPrivate)
68               flags_arg |= MAP_PRIVATE;
69             if (flags & eMmapFlagsAnon)
70               flags_arg |= MAP_ANON;
71 
72             AddressRange mmap_range;
73             if (sc.GetAddressRange(range_scope, 0, use_inline_block_range, mmap_range))
74             {
75                 ClangASTContext *clang_ast_context = process->GetTarget().GetScratchClangASTContext();
76                 lldb::clang_type_t clang_void_ptr_type = clang_ast_context->GetVoidPtrType(false);
77                 ThreadPlanCallFunction *call_function_thread_plan
78                   = new ThreadPlanCallFunction (*thread,
79                                                 mmap_range.GetBaseAddress(),
80                                                 ClangASTType (clang_ast_context->getASTContext(), clang_void_ptr_type),
81                                                 stop_other_threads,
82                                                 discard_on_error,
83                                                 &addr,
84                                                 &length,
85                                                 &prot_arg,
86                                                 &flags_arg,
87                                                 &fd,
88                                                 &offset);
89                 lldb::ThreadPlanSP call_plan_sp (call_function_thread_plan);
90                 if (call_plan_sp)
91                 {
92                     StreamFile error_strm;
93                     // This plan is a utility plan, so set it to discard itself when done.
94                     call_plan_sp->SetIsMasterPlan (true);
95                     call_plan_sp->SetOkayToDiscard(true);
96 
97                     StackFrame *frame = thread->GetStackFrameAtIndex (0).get();
98                     if (frame)
99                     {
100                         ExecutionContext exe_ctx;
101                         frame->CalculateExecutionContext (exe_ctx);
102                         ExecutionResults result = process->RunThreadPlan (exe_ctx,
103                                                                           call_plan_sp,
104                                                                           stop_other_threads,
105                                                                           try_all_threads,
106                                                                           discard_on_error,
107                                                                           single_thread_timeout_usec,
108                                                                           error_strm);
109                         if (result == eExecutionCompleted)
110                         {
111 
112                             allocated_addr = call_plan_sp->GetReturnValueObject()->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
113                             if (process->GetAddressByteSize() == 4)
114                             {
115                                 if (allocated_addr == UINT32_MAX)
116                                     return false;
117                             }
118                             return true;
119                         }
120                     }
121                 }
122             }
123         }
124     }
125 
126     return false;
127 }
128 
129 bool lldb_private::InferiorCallMunmap(Process *process, addr_t addr,
130                                       addr_t length) {
131    Thread *thread = process->GetThreadList().GetSelectedThread().get();
132    if (thread == NULL)
133        return false;
134 
135    const bool append = true;
136    const bool include_symbols = true;
137    const bool include_inlines = false;
138    SymbolContextList sc_list;
139    const uint32_t count
140      = process->GetTarget().GetImages().FindFunctions (ConstString ("munmap"),
141                                                        eFunctionNameTypeFull,
142                                                        include_symbols,
143                                                        include_inlines,
144                                                        append,
145                                                        sc_list);
146    if (count > 0)
147    {
148        SymbolContext sc;
149        if (sc_list.GetContextAtIndex(0, sc))
150        {
151            const uint32_t range_scope = eSymbolContextFunction | eSymbolContextSymbol;
152            const bool use_inline_block_range = false;
153            const bool stop_other_threads = true;
154            const bool discard_on_error = true;
155            const bool try_all_threads = true;
156            const uint32_t single_thread_timeout_usec = 500000;
157 
158            AddressRange munmap_range;
159            if (sc.GetAddressRange(range_scope, 0, use_inline_block_range, munmap_range))
160            {
161                lldb::ThreadPlanSP call_plan_sp (new ThreadPlanCallFunction (*thread,
162                                                                             munmap_range.GetBaseAddress(),
163                                                                             ClangASTType(),
164                                                                             stop_other_threads,
165                                                                             discard_on_error,
166                                                                             &addr,
167                                                                             &length));
168                if (call_plan_sp)
169                {
170                    StreamFile error_strm;
171                    // This plan is a utility plan, so set it to discard itself when done.
172                    call_plan_sp->SetIsMasterPlan (true);
173                    call_plan_sp->SetOkayToDiscard(true);
174 
175                    StackFrame *frame = thread->GetStackFrameAtIndex (0).get();
176                    if (frame)
177                    {
178                        ExecutionContext exe_ctx;
179                        frame->CalculateExecutionContext (exe_ctx);
180                        ExecutionResults result = process->RunThreadPlan (exe_ctx,
181                                                                          call_plan_sp,
182                                                                          stop_other_threads,
183                                                                          try_all_threads,
184                                                                          discard_on_error,
185                                                                          single_thread_timeout_usec,
186                                                                          error_strm);
187                        if (result == eExecutionCompleted)
188                        {
189                            return true;
190                        }
191                    }
192                }
193            }
194        }
195    }
196 
197    return false;
198 }
199