1 //===-- BreakpointResolverAddress.cpp ---------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "lldb/Breakpoint/BreakpointResolverAddress.h"
10 
11 
12 #include "lldb/Breakpoint/BreakpointLocation.h"
13 #include "lldb/Core/Module.h"
14 #include "lldb/Core/Section.h"
15 #include "lldb/Target/Process.h"
16 #include "lldb/Target/Target.h"
17 #include "lldb/Utility/Log.h"
18 #include "lldb/Utility/StreamString.h"
19 
20 using namespace lldb;
21 using namespace lldb_private;
22 
23 //----------------------------------------------------------------------
24 // BreakpointResolverAddress:
25 //----------------------------------------------------------------------
26 BreakpointResolverAddress::BreakpointResolverAddress(
27     Breakpoint *bkpt, const Address &addr, const FileSpec &module_spec)
28     : BreakpointResolver(bkpt, BreakpointResolver::AddressResolver),
29       m_addr(addr), m_resolved_addr(LLDB_INVALID_ADDRESS),
30       m_module_filespec(module_spec) {}
31 
32 BreakpointResolverAddress::BreakpointResolverAddress(Breakpoint *bkpt,
33                                                      const Address &addr)
34     : BreakpointResolver(bkpt, BreakpointResolver::AddressResolver),
35       m_addr(addr), m_resolved_addr(LLDB_INVALID_ADDRESS), m_module_filespec() {
36 }
37 
38 BreakpointResolverAddress::~BreakpointResolverAddress() {}
39 
40 BreakpointResolver *BreakpointResolverAddress::CreateFromStructuredData(
41     Breakpoint *bkpt, const StructuredData::Dictionary &options_dict,
42     Status &error) {
43   llvm::StringRef module_name;
44   lldb::addr_t addr_offset;
45   FileSpec module_filespec;
46   bool success;
47 
48   success = options_dict.GetValueForKeyAsInteger(
49       GetKey(OptionNames::AddressOffset), addr_offset);
50   if (!success) {
51     error.SetErrorString("BRFL::CFSD: Couldn't find address offset entry.");
52     return nullptr;
53   }
54   Address address(addr_offset);
55 
56   success = options_dict.HasKey(GetKey(OptionNames::ModuleName));
57   if (success) {
58     success = options_dict.GetValueForKeyAsString(
59         GetKey(OptionNames::ModuleName), module_name);
60     if (!success) {
61       error.SetErrorString("BRA::CFSD: Couldn't read module name entry.");
62       return nullptr;
63     }
64     module_filespec.SetFile(module_name, FileSpec::Style::native);
65   }
66   return new BreakpointResolverAddress(bkpt, address, module_filespec);
67 }
68 
69 StructuredData::ObjectSP
70 BreakpointResolverAddress::SerializeToStructuredData() {
71   StructuredData::DictionarySP options_dict_sp(
72       new StructuredData::Dictionary());
73   SectionSP section_sp = m_addr.GetSection();
74   if (section_sp) {
75     ModuleSP module_sp = section_sp->GetModule();
76     ConstString module_name;
77     if (module_sp)
78       module_name.SetCString(module_name.GetCString());
79 
80     options_dict_sp->AddStringItem(GetKey(OptionNames::ModuleName),
81                                    module_name.GetCString());
82     options_dict_sp->AddIntegerItem(GetKey(OptionNames::AddressOffset),
83                                     m_addr.GetOffset());
84   } else {
85     options_dict_sp->AddIntegerItem(GetKey(OptionNames::AddressOffset),
86                                     m_addr.GetOffset());
87     if (m_module_filespec) {
88       options_dict_sp->AddStringItem(GetKey(OptionNames::ModuleName),
89                                      m_module_filespec.GetPath());
90     }
91   }
92 
93   return WrapOptionsDict(options_dict_sp);
94   return StructuredData::ObjectSP();
95 }
96 
97 void BreakpointResolverAddress::ResolveBreakpoint(SearchFilter &filter) {
98   // If the address is not section relative, then we should not try to re-
99   // resolve it, it is just some random address and we wouldn't know what to do
100   // on reload.  But if it is section relative, we need to re-resolve it since
101   // the section it's in may have shifted on re-run.
102   bool re_resolve = false;
103   if (m_addr.GetSection() || m_module_filespec)
104     re_resolve = true;
105   else if (m_breakpoint->GetNumLocations() == 0)
106     re_resolve = true;
107 
108   if (re_resolve)
109     BreakpointResolver::ResolveBreakpoint(filter);
110 }
111 
112 void BreakpointResolverAddress::ResolveBreakpointInModules(
113     SearchFilter &filter, ModuleList &modules) {
114   // See comment in ResolveBreakpoint.
115   bool re_resolve = false;
116   if (m_addr.GetSection())
117     re_resolve = true;
118   else if (m_breakpoint->GetNumLocations() == 0)
119     re_resolve = true;
120 
121   if (re_resolve)
122     BreakpointResolver::ResolveBreakpointInModules(filter, modules);
123 }
124 
125 Searcher::CallbackReturn
126 BreakpointResolverAddress::SearchCallback(SearchFilter &filter,
127                                           SymbolContext &context, Address *addr,
128                                           bool containing) {
129   assert(m_breakpoint != NULL);
130 
131   if (filter.AddressPasses(m_addr)) {
132     if (m_breakpoint->GetNumLocations() == 0) {
133       // If the address is just an offset, and we're given a module, see if we
134       // can find the appropriate module loaded in the binary, and fix up
135       // m_addr to use that.
136       if (!m_addr.IsSectionOffset() && m_module_filespec) {
137         Target &target = m_breakpoint->GetTarget();
138         ModuleSpec module_spec(m_module_filespec);
139         ModuleSP module_sp = target.GetImages().FindFirstModule(module_spec);
140         if (module_sp) {
141           Address tmp_address;
142           if (module_sp->ResolveFileAddress(m_addr.GetOffset(), tmp_address))
143             m_addr = tmp_address;
144         }
145       }
146 
147       m_resolved_addr = m_addr.GetLoadAddress(&m_breakpoint->GetTarget());
148       BreakpointLocationSP bp_loc_sp(AddLocation(m_addr));
149       if (bp_loc_sp && !m_breakpoint->IsInternal()) {
150         StreamString s;
151         bp_loc_sp->GetDescription(&s, lldb::eDescriptionLevelVerbose);
152         Log *log(
153             lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
154         if (log)
155           log->Printf("Added location: %s\n", s.GetData());
156       }
157     } else {
158       BreakpointLocationSP loc_sp = m_breakpoint->GetLocationAtIndex(0);
159       lldb::addr_t cur_load_location =
160           m_addr.GetLoadAddress(&m_breakpoint->GetTarget());
161       if (cur_load_location != m_resolved_addr) {
162         m_resolved_addr = cur_load_location;
163         loc_sp->ClearBreakpointSite();
164         loc_sp->ResolveBreakpointSite();
165       }
166     }
167   }
168   return Searcher::eCallbackReturnStop;
169 }
170 
171 lldb::SearchDepth BreakpointResolverAddress::GetDepth() {
172   return lldb::eSearchDepthTarget;
173 }
174 
175 void BreakpointResolverAddress::GetDescription(Stream *s) {
176   s->PutCString("address = ");
177   m_addr.Dump(s, m_breakpoint->GetTarget().GetProcessSP().get(),
178               Address::DumpStyleModuleWithFileAddress,
179               Address::DumpStyleLoadAddress);
180 }
181 
182 void BreakpointResolverAddress::Dump(Stream *s) const {}
183 
184 lldb::BreakpointResolverSP
185 BreakpointResolverAddress::CopyForBreakpoint(Breakpoint &breakpoint) {
186   lldb::BreakpointResolverSP ret_sp(
187       new BreakpointResolverAddress(&breakpoint, m_addr));
188   return ret_sp;
189 }
190