ClangExpressionDeclMap.cpp revision 336a0002b94c7f23573ec613c4d4ac89a67fd299
1//===-- ClangExpressionDeclMap.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 "lldb/Expression/ClangExpressionDeclMap.h"
11
12// C Includes
13// C++ Includes
14// Other libraries and framework includes
15// Project includes
16#include "lldb/lldb-private.h"
17#include "lldb/Core/Address.h"
18#include "lldb/Core/Error.h"
19#include "lldb/Core/Log.h"
20#include "lldb/Core/Module.h"
21#include "lldb/Expression/ClangASTSource.h"
22#include "lldb/Symbol/ClangASTContext.h"
23#include "lldb/Symbol/CompileUnit.h"
24#include "lldb/Symbol/Function.h"
25#include "lldb/Symbol/ObjectFile.h"
26#include "lldb/Symbol/SymbolContext.h"
27#include "lldb/Symbol/Type.h"
28#include "lldb/Symbol/TypeList.h"
29#include "lldb/Symbol/Variable.h"
30#include "lldb/Symbol/VariableList.h"
31#include "lldb/Target/Process.h"
32#include "lldb/Target/StackFrame.h"
33#include "lldb/Target/ExecutionContext.h"
34
35using namespace lldb_private;
36using namespace clang;
37
38ClangExpressionDeclMap::ClangExpressionDeclMap(ExecutionContext *exe_ctx) :
39    m_exe_ctx(exe_ctx),
40    m_struct_laid_out(false),
41    m_materialized_location(0)
42{
43    if (exe_ctx && exe_ctx->frame)
44        m_sym_ctx = new SymbolContext(exe_ctx->frame->GetSymbolContext(lldb::eSymbolContextEverything));
45    else
46        m_sym_ctx = NULL;
47}
48
49ClangExpressionDeclMap::~ClangExpressionDeclMap()
50{
51    uint32_t num_tuples = m_tuples.size ();
52    uint32_t tuple_index;
53
54    for (tuple_index = 0; tuple_index < num_tuples; ++tuple_index)
55        delete m_tuples[tuple_index].m_value;
56
57    if (m_sym_ctx)
58        delete m_sym_ctx;
59}
60
61bool
62ClangExpressionDeclMap::GetIndexForDecl (uint32_t &index,
63                                         const clang::Decl *decl)
64{
65    uint32_t num_tuples = m_tuples.size ();
66    uint32_t tuple_index;
67
68    for (tuple_index = 0; tuple_index < num_tuples; ++tuple_index)
69    {
70        if (m_tuples[tuple_index].m_decl == decl)
71        {
72            index = tuple_index;
73            return true;
74        }
75    }
76
77    return false;
78}
79
80// Interface for IRForTarget
81
82bool
83ClangExpressionDeclMap::AddValueToStruct (llvm::Value *value,
84                                          const clang::NamedDecl *decl,
85                                          std::string &name,
86                                          void *type,
87                                          size_t size,
88                                          off_t alignment)
89{
90    m_struct_laid_out = false;
91
92    StructMemberIterator iter;
93
94    for (iter = m_members.begin();
95         iter != m_members.end();
96         ++iter)
97    {
98        if (iter->m_decl == decl)
99            return true;
100    }
101
102    StructMember member;
103
104    member.m_value      = value;
105    member.m_decl       = decl;
106    member.m_name       = name;
107    member.m_type       = type;
108    member.m_offset     = 0;
109    member.m_size       = size;
110    member.m_alignment  = alignment;
111
112    m_members.push_back(member);
113
114    return true;
115}
116
117bool
118ClangExpressionDeclMap::DoStructLayout ()
119{
120    if (m_struct_laid_out)
121        return true;
122
123    StructMemberIterator iter;
124
125    off_t cursor = 0;
126
127    m_struct_alignment = 0;
128    m_struct_size = 0;
129
130    for (iter = m_members.begin();
131         iter != m_members.end();
132         ++iter)
133    {
134        if (iter == m_members.begin())
135            m_struct_alignment = iter->m_alignment;
136
137        if (cursor % iter->m_alignment)
138            cursor += (iter->m_alignment - (cursor % iter->m_alignment));
139
140        iter->m_offset = cursor;
141        cursor += iter->m_size;
142    }
143
144    m_struct_size = cursor;
145
146    m_struct_laid_out = true;
147    return true;
148}
149
150bool ClangExpressionDeclMap::GetStructInfo (uint32_t &num_elements,
151                                            size_t &size,
152                                            off_t &alignment)
153{
154    if (!m_struct_laid_out)
155        return false;
156
157    num_elements = m_members.size();
158    size = m_struct_size;
159    alignment = m_struct_alignment;
160
161    return true;
162}
163
164bool
165ClangExpressionDeclMap::GetStructElement (const clang::NamedDecl *&decl,
166                                          llvm::Value *&value,
167                                          off_t &offset,
168                                          uint32_t index)
169{
170    if (!m_struct_laid_out)
171        return false;
172
173    if (index >= m_members.size())
174        return false;
175
176    decl = m_members[index].m_decl;
177    value = m_members[index].m_value;
178    offset = m_members[index].m_offset;
179
180    return true;
181}
182
183// Interface for DwarfExpression
184Value
185*ClangExpressionDeclMap::GetValueForIndex (uint32_t index)
186{
187    if (index >= m_tuples.size ())
188        return NULL;
189
190    return m_tuples[index].m_value;
191}
192
193// Interface for CommandObjectExpression
194lldb::addr_t
195ClangExpressionDeclMap::Materialize (ExecutionContext *exe_ctx, Error &err)
196{
197    Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS);
198
199    if (!m_struct_laid_out)
200    {
201        err.SetErrorString("Structure hasn't been laid out yet");
202        return LLDB_INVALID_ADDRESS;
203    }
204
205    if (m_materialized_location)
206    {
207        exe_ctx->process->DeallocateMemory(m_materialized_location);
208        m_materialized_location = 0;
209    }
210
211    if (!exe_ctx)
212    {
213        err.SetErrorString("Received null execution context");
214        return LLDB_INVALID_ADDRESS;
215    }
216
217    const SymbolContext &sym_ctx(exe_ctx->frame->GetSymbolContext(lldb::eSymbolContextEverything));
218
219    StructMemberIterator iter;
220
221    lldb::addr_t mem = exe_ctx->process->AllocateMemory(m_struct_alignment + m_struct_size,
222                                                        lldb::ePermissionsReadable | lldb::ePermissionsWritable,
223                                                        err);
224
225    if (mem == LLDB_INVALID_ADDRESS)
226        return LLDB_INVALID_ADDRESS;
227
228    m_materialized_location = mem;
229
230    lldb::addr_t aligned_mem = mem;
231
232    if (aligned_mem % m_struct_alignment)
233    {
234        aligned_mem += (m_struct_alignment - (aligned_mem % m_struct_alignment));
235    }
236
237    for (iter = m_members.begin();
238         iter != m_members.end();
239         ++iter)
240    {
241        uint32_t tuple_index;
242
243        if (!GetIndexForDecl(tuple_index, iter->m_decl))
244        {
245            if (iter->m_name.find("___clang_expr_result") == std::string::npos)
246            {
247                err.SetErrorStringWithFormat("Unexpected variable %s", iter->m_name.c_str());
248                return false;
249            }
250
251            if (log)
252                log->Printf("Found special result variable %s", iter->m_name.c_str());
253
254            continue;
255        }
256
257        Tuple &tuple(m_tuples[tuple_index]);
258
259        if (!MaterializeOneVariable(*exe_ctx, sym_ctx, iter->m_name.c_str(), tuple.m_orig_type, tuple.m_ast_context, aligned_mem + iter->m_offset, err))
260            return false;
261    }
262
263    return aligned_mem;
264}
265
266Variable*
267ClangExpressionDeclMap::FindVariableInScope(const SymbolContext &sym_ctx,
268                                            const char *name,
269                                            void *type,
270                                            clang::ASTContext *ast_context)
271{
272    Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS);
273
274    Function *function(m_sym_ctx->function);
275    Block *block(m_sym_ctx->block);
276
277    if (!function || !block)
278    {
279        if (log)
280            log->Printf("function = %p, block = %p", function, block);
281        return NULL;
282    }
283
284    BlockList& blocks(function->GetBlocks(true));
285
286    ConstString name_cs(name);
287
288    lldb::user_id_t current_block_id;
289
290    for (current_block_id = block->GetID();
291         current_block_id != Block::InvalidID;
292         current_block_id = blocks.GetParent(current_block_id))
293    {
294        Block *current_block(blocks.GetBlockByID(current_block_id));
295
296        lldb::VariableListSP var_list = current_block->GetVariableList(false, true);
297
298        if (!var_list)
299            continue;
300
301        lldb::VariableSP var = var_list->FindVariable(name_cs);
302
303        if (!var)
304            continue;
305
306        // var->GetType()->GetClangAST() is the program's AST context and holds
307        // var->GetType()->GetOpaqueClangQualType().
308
309        // type is m_type for one of the struct members, which was added by
310        // AddValueToStruct.  That type was extracted from the AST context of
311        // the compiler in IRForTarget.  The original for the type was copied
312        // out of the program's AST context by AddOneVariable.
313
314        // So that we can compare these two without having to copy back
315        // something we already had in the original AST context, we maintain
316        // m_orig_type and m_ast_context (which are passed into
317        // MaterializeOneVariable by Materialize) for each variable.
318
319        if (!type)
320            return var.get();
321
322        if (ast_context == var->GetType()->GetClangAST())
323        {
324            if (!ClangASTContext::AreTypesSame(ast_context, type, var->GetType()->GetOpaqueClangQualType()))
325                continue;
326        }
327        else
328        {
329            if (log)
330                log->PutCString("Skipping a candidate variable because of different AST contexts");
331            continue;
332        }
333
334        return var.get();
335    }
336
337    {
338        CompileUnit *compile_unit = m_sym_ctx->comp_unit;
339
340        if (!compile_unit)
341        {
342            if (log)
343                log->Printf("compile_unit = %p", compile_unit);
344            return NULL;
345        }
346
347        lldb::VariableListSP var_list = compile_unit->GetVariableList(true);
348
349        if (!var_list)
350            return NULL;
351
352        lldb::VariableSP var = var_list->FindVariable(name_cs);
353
354        if (!var)
355            return NULL;
356
357        if (!type)
358            return var.get();
359
360        if (ast_context == var->GetType()->GetClangAST())
361        {
362            if (!ClangASTContext::AreTypesSame(ast_context, type, var->GetType()->GetOpaqueClangQualType()))
363                return NULL;
364        }
365        else
366        {
367            if (log)
368                log->PutCString("Skipping a candidate variable because of different AST contexts");
369            return NULL;
370        }
371
372        return var.get();
373    }
374
375    return NULL;
376}
377
378bool
379ClangExpressionDeclMap::MaterializeOneVariable(ExecutionContext &exe_ctx,
380                                               const SymbolContext &sym_ctx,
381                                               const char *name,
382                                               void *type,
383                                               clang::ASTContext *ast_context,
384                                               lldb::addr_t addr,
385                                               Error &err)
386{
387    Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS);
388
389    Variable *var = FindVariableInScope(sym_ctx, name, type, ast_context);
390
391    if (!var)
392    {
393        err.SetErrorStringWithFormat("Couldn't find %s with appropriate type", name);
394        return false;
395    }
396
397    log->Printf("Materializing %s with type %p", name, type);
398
399    std::auto_ptr<Value> location_value(GetVariableValue(exe_ctx,
400                                                         var,
401                                                         ast_context));
402
403    if (!location_value.get())
404    {
405        err.SetErrorStringWithFormat("Couldn't get value for %s", name);
406        return false;
407    }
408
409    if (location_value->GetValueType() == Value::eValueTypeLoadAddress)
410    {
411        lldb::addr_t src_addr = location_value->GetScalar().ULongLong();
412
413        size_t bit_size = ClangASTContext::GetTypeBitSize(ast_context, type);
414        size_t byte_size = bit_size % 8 ? ((bit_size + 8) / 8) : (bit_size / 8);
415
416        DataBufferHeap data;
417        data.SetByteSize(byte_size);
418
419        Error error;
420        if (exe_ctx.process->ReadMemory (src_addr, data.GetBytes(), byte_size, error) != byte_size)
421        {
422            err.SetErrorStringWithFormat ("Couldn't read a composite type from the target: %s", error.AsCString());
423            return false;
424        }
425
426        if (exe_ctx.process->WriteMemory (addr, data.GetBytes(), byte_size, error) != byte_size)
427        {
428            err.SetErrorStringWithFormat ("Couldn't write a composite type to the target: %s", error.AsCString());
429            return false;
430        }
431
432        if (log)
433            log->Printf("Copied from 0x%llx to 0x%llx", (uint64_t)src_addr, (uint64_t)addr);
434    }
435    else
436    {
437        StreamString ss;
438
439        location_value->Dump(&ss);
440
441        err.SetErrorStringWithFormat("%s has a value of unhandled type: %s", name, ss.GetString().c_str());
442    }
443
444    return true;
445}
446
447// Interface for ClangASTSource
448void
449ClangExpressionDeclMap::GetDecls(NameSearchContext &context,
450                                 const char *name)
451{
452    Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS);
453
454    if (log)
455        log->Printf("Hunting for a definition for %s", name);
456
457    // Back out in all cases where we're not fully initialized
458    if (!m_exe_ctx || !m_exe_ctx->frame || !m_sym_ctx)
459        return;
460
461    Function *function = m_sym_ctx->function;
462
463    if (!function)
464    {
465        if (log)
466            log->Printf("Can't evaluate an expression when not in a function");
467        return;
468    }
469
470    ConstString name_cs(name);
471
472    Function *fn = m_sym_ctx->FindFunctionByName(name_cs.GetCString());
473
474    if (fn)
475        AddOneFunction(context, fn);
476
477    Variable *var = FindVariableInScope(*m_sym_ctx, name);
478
479    if (var)
480        AddOneVariable(context, var);
481}
482
483Value *
484ClangExpressionDeclMap::GetVariableValue(ExecutionContext &exe_ctx,
485                                         Variable *var,
486                                         clang::ASTContext *target_ast_context,
487                                         void **opaque_type,
488                                         clang::ASTContext **found_ast_context)
489{
490    Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS);
491
492    Type *var_type = var->GetType();
493
494    if (!var_type)
495    {
496        if (log)
497            log->PutCString("Skipped a definition because it has no type");
498        return NULL;
499    }
500
501    void *var_opaque_type = var_type->GetOpaqueClangQualType();
502
503    if (!var_opaque_type)
504    {
505        if (log)
506            log->PutCString("Skipped a definition because it has no Clang type");
507        return NULL;
508    }
509
510    TypeList *type_list = var_type->GetTypeList();
511
512    if (!type_list)
513    {
514        if (log)
515            log->PutCString("Skipped a definition because the type has no associated type list");
516        return NULL;
517    }
518
519    clang::ASTContext *exe_ast_ctx = type_list->GetClangASTContext().getASTContext();
520
521    if (!exe_ast_ctx)
522    {
523        if (log)
524            log->PutCString("There is no AST context for the current execution context");
525        return NULL;
526    }
527
528    DWARFExpression &var_location_expr = var->LocationExpression();
529
530    std::auto_ptr<Value> var_location(new Value);
531
532    Error err;
533
534    if (!var_location_expr.Evaluate(&exe_ctx, exe_ast_ctx, NULL, *var_location.get(), &err))
535    {
536        if (log)
537            log->Printf("Error evaluating location: %s", err.AsCString());
538        return NULL;
539    }
540
541    clang::ASTContext *var_ast_context = type_list->GetClangASTContext().getASTContext();
542
543    void *type_to_use;
544
545    if (target_ast_context)
546        type_to_use = ClangASTContext::CopyType(target_ast_context, var_ast_context, var_opaque_type);
547    else
548        type_to_use = var_opaque_type;
549
550    if (var_location.get()->GetContextType() == Value::eContextTypeInvalid)
551        var_location.get()->SetContext(Value::eContextTypeOpaqueClangQualType, type_to_use);
552
553    if (var_location.get()->GetValueType() == Value::eValueTypeFileAddress)
554    {
555        SymbolContext var_sc;
556        var->CalculateSymbolContext(&var_sc);
557
558        if (!var_sc.module_sp)
559            return NULL;
560
561        ObjectFile *object_file = var_sc.module_sp->GetObjectFile();
562
563        if (!object_file)
564            return NULL;
565
566        Address so_addr(var_location->GetScalar().ULongLong(), object_file->GetSectionList());
567
568        lldb::addr_t load_addr = so_addr.GetLoadAddress(m_exe_ctx->process);
569
570        var_location->GetScalar() = load_addr;
571        var_location->SetValueType(Value::eValueTypeLoadAddress);
572    }
573
574    if (opaque_type)
575        *opaque_type = var_opaque_type;
576
577    if (found_ast_context)
578        *found_ast_context = var_ast_context;
579
580    return var_location.release();
581}
582
583void
584ClangExpressionDeclMap::AddOneVariable(NameSearchContext &context,
585                                       Variable* var)
586{
587    Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS);
588
589    void *var_opaque_type = NULL;
590    clang::ASTContext *var_ast_context = NULL;
591
592    Value *var_location = GetVariableValue(*m_exe_ctx,
593                                           var,
594                                           context.GetASTContext(),
595                                           &var_opaque_type,
596                                           &var_ast_context);
597
598    NamedDecl *var_decl = context.AddVarDecl(var_opaque_type);
599
600    Tuple tuple;
601
602    tuple.m_decl        = var_decl;
603    tuple.m_value       = var_location;
604    tuple.m_orig_type   = var_opaque_type;
605    tuple.m_ast_context = var_ast_context;
606
607    m_tuples.push_back(tuple);
608
609    if (log)
610        log->PutCString("Found variable");
611}
612
613void
614ClangExpressionDeclMap::AddOneFunction(NameSearchContext &context,
615                                       Function* fun)
616{
617    Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS);
618
619    Type *fun_type = fun->GetType();
620
621    if (!fun_type)
622    {
623        if (log)
624            log->PutCString("Skipped a function because it has no type");
625        return;
626    }
627
628    void *fun_opaque_type = fun_type->GetOpaqueClangQualType();
629
630    if (!fun_opaque_type)
631    {
632        if (log)
633            log->PutCString("Skipped a function because it has no Clang type");
634        return;
635    }
636
637    std::auto_ptr<Value> fun_location(new Value);
638
639    const Address &fun_address = fun->GetAddressRange().GetBaseAddress();
640    lldb::addr_t load_addr = fun_address.GetLoadAddress(m_exe_ctx->process);
641    fun_location->SetValueType(Value::eValueTypeLoadAddress);
642    fun_location->GetScalar() = load_addr;
643
644    TypeList *type_list = fun_type->GetTypeList();
645    clang::ASTContext *fun_ast_context = type_list->GetClangASTContext().getASTContext();
646    void *copied_type = ClangASTContext::CopyType(context.GetASTContext(), fun_ast_context, fun_opaque_type);
647
648    NamedDecl *fun_decl = context.AddFunDecl(copied_type);
649
650    Tuple tuple;
651
652    tuple.m_decl        = fun_decl;
653    tuple.m_value       = fun_location.release();
654    tuple.m_orig_type   = fun_opaque_type;
655    tuple.m_ast_context = fun_ast_context;
656
657    m_tuples.push_back(tuple);
658
659    if (log)
660        log->PutCString("Found function");
661}
662