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