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