1*0b57cec5SDimitry Andric //===-- SectionLoadHistory.cpp --------------------------------------------===//
2*0b57cec5SDimitry Andric //
3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric //
7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric 
9*0b57cec5SDimitry Andric #include "lldb/Target/SectionLoadHistory.h"
10*0b57cec5SDimitry Andric 
11*0b57cec5SDimitry Andric #include "lldb/Target/SectionLoadList.h"
12*0b57cec5SDimitry Andric #include "lldb/Utility/Stream.h"
13*0b57cec5SDimitry Andric 
14*0b57cec5SDimitry Andric using namespace lldb;
15*0b57cec5SDimitry Andric using namespace lldb_private;
16*0b57cec5SDimitry Andric 
IsEmpty() const17*0b57cec5SDimitry Andric bool SectionLoadHistory::IsEmpty() const {
18*0b57cec5SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(m_mutex);
19*0b57cec5SDimitry Andric   return m_stop_id_to_section_load_list.empty();
20*0b57cec5SDimitry Andric }
21*0b57cec5SDimitry Andric 
Clear()22*0b57cec5SDimitry Andric void SectionLoadHistory::Clear() {
23*0b57cec5SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(m_mutex);
24*0b57cec5SDimitry Andric   m_stop_id_to_section_load_list.clear();
25*0b57cec5SDimitry Andric }
26*0b57cec5SDimitry Andric 
GetLastStopID() const27*0b57cec5SDimitry Andric uint32_t SectionLoadHistory::GetLastStopID() const {
28*0b57cec5SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(m_mutex);
29*0b57cec5SDimitry Andric   if (m_stop_id_to_section_load_list.empty())
30*0b57cec5SDimitry Andric     return 0;
31*0b57cec5SDimitry Andric   else
32*0b57cec5SDimitry Andric     return m_stop_id_to_section_load_list.rbegin()->first;
33*0b57cec5SDimitry Andric }
34*0b57cec5SDimitry Andric 
35*0b57cec5SDimitry Andric SectionLoadList *
GetSectionLoadListForStopID(uint32_t stop_id,bool read_only)36*0b57cec5SDimitry Andric SectionLoadHistory::GetSectionLoadListForStopID(uint32_t stop_id,
37*0b57cec5SDimitry Andric                                                 bool read_only) {
38*0b57cec5SDimitry Andric   if (!m_stop_id_to_section_load_list.empty()) {
39*0b57cec5SDimitry Andric     if (read_only) {
40*0b57cec5SDimitry Andric       // The section load list is for reading data only so we don't need to
41*0b57cec5SDimitry Andric       // create a new SectionLoadList for the current stop ID, just return the
42*0b57cec5SDimitry Andric       // section load list for the stop ID that is equal to or less than the
43*0b57cec5SDimitry Andric       // current stop ID
44*0b57cec5SDimitry Andric       if (stop_id == eStopIDNow) {
45*0b57cec5SDimitry Andric         // If we are asking for the latest and greatest value, it is always at
46*0b57cec5SDimitry Andric         // the end of our list because that will be the highest stop ID.
47*0b57cec5SDimitry Andric         StopIDToSectionLoadList::reverse_iterator rpos =
48*0b57cec5SDimitry Andric             m_stop_id_to_section_load_list.rbegin();
49*0b57cec5SDimitry Andric         return rpos->second.get();
50*0b57cec5SDimitry Andric       } else {
51*0b57cec5SDimitry Andric         StopIDToSectionLoadList::iterator pos =
52*0b57cec5SDimitry Andric             m_stop_id_to_section_load_list.lower_bound(stop_id);
53*0b57cec5SDimitry Andric         if (pos != m_stop_id_to_section_load_list.end() &&
54*0b57cec5SDimitry Andric             pos->first == stop_id)
55*0b57cec5SDimitry Andric           return pos->second.get();
56*0b57cec5SDimitry Andric         else if (pos != m_stop_id_to_section_load_list.begin()) {
57*0b57cec5SDimitry Andric           --pos;
58*0b57cec5SDimitry Andric           return pos->second.get();
59*0b57cec5SDimitry Andric         }
60*0b57cec5SDimitry Andric       }
61*0b57cec5SDimitry Andric     } else {
62*0b57cec5SDimitry Andric       // You can only use "eStopIDNow" when reading from the section load
63*0b57cec5SDimitry Andric       // history
64*0b57cec5SDimitry Andric       assert(stop_id != eStopIDNow);
65*0b57cec5SDimitry Andric 
66*0b57cec5SDimitry Andric       // We are updating the section load list (not read only), so if the stop
67*0b57cec5SDimitry Andric       // ID passed in isn't the same as the last stop ID in our collection,
68*0b57cec5SDimitry Andric       // then create a new node using the current stop ID
69*0b57cec5SDimitry Andric       StopIDToSectionLoadList::iterator pos =
70*0b57cec5SDimitry Andric           m_stop_id_to_section_load_list.lower_bound(stop_id);
71*0b57cec5SDimitry Andric       if (pos != m_stop_id_to_section_load_list.end() &&
72*0b57cec5SDimitry Andric           pos->first == stop_id) {
73*0b57cec5SDimitry Andric         // We already have an entry for this value
74*0b57cec5SDimitry Andric         return pos->second.get();
75*0b57cec5SDimitry Andric       }
76*0b57cec5SDimitry Andric 
77*0b57cec5SDimitry Andric       // We must make a new section load list that is based on the last valid
78*0b57cec5SDimitry Andric       // section load list, so here we copy the last section load list and add
79*0b57cec5SDimitry Andric       // a new node for the current stop ID.
80*0b57cec5SDimitry Andric       StopIDToSectionLoadList::reverse_iterator rpos =
81*0b57cec5SDimitry Andric           m_stop_id_to_section_load_list.rbegin();
82*0b57cec5SDimitry Andric       SectionLoadListSP section_load_list_sp(
83*0b57cec5SDimitry Andric           new SectionLoadList(*rpos->second));
84*0b57cec5SDimitry Andric       m_stop_id_to_section_load_list[stop_id] = section_load_list_sp;
85*0b57cec5SDimitry Andric       return section_load_list_sp.get();
86*0b57cec5SDimitry Andric     }
87*0b57cec5SDimitry Andric   }
88*0b57cec5SDimitry Andric   SectionLoadListSP section_load_list_sp(new SectionLoadList());
89*0b57cec5SDimitry Andric   if (stop_id == eStopIDNow)
90*0b57cec5SDimitry Andric     stop_id = 0;
91*0b57cec5SDimitry Andric   m_stop_id_to_section_load_list[stop_id] = section_load_list_sp;
92*0b57cec5SDimitry Andric   return section_load_list_sp.get();
93*0b57cec5SDimitry Andric }
94*0b57cec5SDimitry Andric 
GetCurrentSectionLoadList()95*0b57cec5SDimitry Andric SectionLoadList &SectionLoadHistory::GetCurrentSectionLoadList() {
96*0b57cec5SDimitry Andric   const bool read_only = true;
97*0b57cec5SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(m_mutex);
98*0b57cec5SDimitry Andric   SectionLoadList *section_load_list =
99*0b57cec5SDimitry Andric       GetSectionLoadListForStopID(eStopIDNow, read_only);
100*0b57cec5SDimitry Andric   assert(section_load_list != nullptr);
101*0b57cec5SDimitry Andric   return *section_load_list;
102*0b57cec5SDimitry Andric }
103*0b57cec5SDimitry Andric 
104*0b57cec5SDimitry Andric addr_t
GetSectionLoadAddress(uint32_t stop_id,const lldb::SectionSP & section_sp)105*0b57cec5SDimitry Andric SectionLoadHistory::GetSectionLoadAddress(uint32_t stop_id,
106*0b57cec5SDimitry Andric                                           const lldb::SectionSP &section_sp) {
107*0b57cec5SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(m_mutex);
108*0b57cec5SDimitry Andric   const bool read_only = true;
109*0b57cec5SDimitry Andric   SectionLoadList *section_load_list =
110*0b57cec5SDimitry Andric       GetSectionLoadListForStopID(stop_id, read_only);
111*0b57cec5SDimitry Andric   return section_load_list->GetSectionLoadAddress(section_sp);
112*0b57cec5SDimitry Andric }
113*0b57cec5SDimitry Andric 
ResolveLoadAddress(uint32_t stop_id,addr_t load_addr,Address & so_addr)114*0b57cec5SDimitry Andric bool SectionLoadHistory::ResolveLoadAddress(uint32_t stop_id, addr_t load_addr,
115*0b57cec5SDimitry Andric                                             Address &so_addr) {
116*0b57cec5SDimitry Andric   // First find the top level section that this load address exists in
117*0b57cec5SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(m_mutex);
118*0b57cec5SDimitry Andric   const bool read_only = true;
119*0b57cec5SDimitry Andric   SectionLoadList *section_load_list =
120*0b57cec5SDimitry Andric       GetSectionLoadListForStopID(stop_id, read_only);
121*0b57cec5SDimitry Andric   return section_load_list->ResolveLoadAddress(load_addr, so_addr);
122*0b57cec5SDimitry Andric }
123*0b57cec5SDimitry Andric 
SetSectionLoadAddress(uint32_t stop_id,const lldb::SectionSP & section_sp,addr_t load_addr,bool warn_multiple)124*0b57cec5SDimitry Andric bool SectionLoadHistory::SetSectionLoadAddress(
125*0b57cec5SDimitry Andric     uint32_t stop_id, const lldb::SectionSP &section_sp, addr_t load_addr,
126*0b57cec5SDimitry Andric     bool warn_multiple) {
127*0b57cec5SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(m_mutex);
128*0b57cec5SDimitry Andric   const bool read_only = false;
129*0b57cec5SDimitry Andric   SectionLoadList *section_load_list =
130*0b57cec5SDimitry Andric       GetSectionLoadListForStopID(stop_id, read_only);
131*0b57cec5SDimitry Andric   return section_load_list->SetSectionLoadAddress(section_sp, load_addr,
132*0b57cec5SDimitry Andric                                                   warn_multiple);
133*0b57cec5SDimitry Andric }
134*0b57cec5SDimitry Andric 
135*0b57cec5SDimitry Andric size_t
SetSectionUnloaded(uint32_t stop_id,const lldb::SectionSP & section_sp)136*0b57cec5SDimitry Andric SectionLoadHistory::SetSectionUnloaded(uint32_t stop_id,
137*0b57cec5SDimitry Andric                                        const lldb::SectionSP &section_sp) {
138*0b57cec5SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(m_mutex);
139*0b57cec5SDimitry Andric   const bool read_only = false;
140*0b57cec5SDimitry Andric   SectionLoadList *section_load_list =
141*0b57cec5SDimitry Andric       GetSectionLoadListForStopID(stop_id, read_only);
142*0b57cec5SDimitry Andric   return section_load_list->SetSectionUnloaded(section_sp);
143*0b57cec5SDimitry Andric }
144*0b57cec5SDimitry Andric 
SetSectionUnloaded(uint32_t stop_id,const lldb::SectionSP & section_sp,addr_t load_addr)145*0b57cec5SDimitry Andric bool SectionLoadHistory::SetSectionUnloaded(uint32_t stop_id,
146*0b57cec5SDimitry Andric                                             const lldb::SectionSP &section_sp,
147*0b57cec5SDimitry Andric                                             addr_t load_addr) {
148*0b57cec5SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(m_mutex);
149*0b57cec5SDimitry Andric   const bool read_only = false;
150*0b57cec5SDimitry Andric   SectionLoadList *section_load_list =
151*0b57cec5SDimitry Andric       GetSectionLoadListForStopID(stop_id, read_only);
152*0b57cec5SDimitry Andric   return section_load_list->SetSectionUnloaded(section_sp, load_addr);
153*0b57cec5SDimitry Andric }
154*0b57cec5SDimitry Andric 
Dump(Stream & s,Target * target)155*0b57cec5SDimitry Andric void SectionLoadHistory::Dump(Stream &s, Target *target) {
156*0b57cec5SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(m_mutex);
157*0b57cec5SDimitry Andric   StopIDToSectionLoadList::iterator pos,
158*0b57cec5SDimitry Andric       end = m_stop_id_to_section_load_list.end();
159*0b57cec5SDimitry Andric   for (pos = m_stop_id_to_section_load_list.begin(); pos != end; ++pos) {
160*0b57cec5SDimitry Andric     s.Printf("StopID = %u:\n", pos->first);
161*0b57cec5SDimitry Andric     pos->second->Dump(s, target);
162*0b57cec5SDimitry Andric     s.EOL();
163*0b57cec5SDimitry Andric   }
164*0b57cec5SDimitry Andric }
165