1 //////////////////////////////////////////////////////////////////////// 2 // 3 // Copyright (C) 1993-2021 The Octave Project Developers 4 // 5 // See the file COPYRIGHT.md in the top-level directory of this 6 // distribution or <https://octave.org/copyright/>. 7 // 8 // This file is part of Octave. 9 // 10 // Octave is free software: you can redistribute it and/or modify it 11 // under the terms of the GNU General Public License as published by 12 // the Free Software Foundation, either version 3 of the License, or 13 // (at your option) any later version. 14 // 15 // Octave is distributed in the hope that it will be useful, but 16 // WITHOUT ANY WARRANTY; without even the implied warranty of 17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 // GNU General Public License for more details. 19 // 20 // You should have received a copy of the GNU General Public License 21 // along with Octave; see the file COPYING. If not, see 22 // <https://www.gnu.org/licenses/>. 23 // 24 //////////////////////////////////////////////////////////////////////// 25 26 #if defined (HAVE_CONFIG_H) 27 # include "config.h" 28 #endif 29 30 #include <iostream> 31 #include <list> 32 33 #include "file-stat.h" 34 #include "oct-env.h" 35 #include "oct-time.h" 36 37 #include "defun.h" 38 #include "dynamic-ld.h" 39 #include "interpreter-private.h" 40 #include "interpreter.h" 41 #include "ov-fcn.h" 42 #include "ov-dld-fcn.h" 43 #include "ov-mex-fcn.h" 44 #include "parse.h" 45 #include "unwind-prot.h" 46 #include "utils.h" 47 #include "variables.h" 48 49 #define STRINGIFY(s) STRINGIFY1(s) 50 #define STRINGIFY1(s) #s 51 52 namespace octave 53 { 54 void append(const dynamic_library & shl)55 dynamic_loader::shlibs_list::append (const dynamic_library& shl) 56 { 57 m_lib_list.push_back (shl); 58 } 59 60 std::list<std::string> remove(dynamic_library & shl)61 dynamic_loader::shlibs_list::remove (dynamic_library& shl) 62 { 63 std::list<std::string> removed_fcns; 64 65 for (auto p = m_lib_list.begin (); p != m_lib_list.end (); p++) 66 { 67 if (*p == shl) 68 { 69 m_lib_list.erase (p); 70 71 removed_fcns = shl.close (); 72 73 break; 74 } 75 } 76 77 return removed_fcns; 78 } 79 80 dynamic_library find_file(const std::string & file_name) const81 dynamic_loader::shlibs_list::find_file (const std::string& file_name) const 82 { 83 dynamic_library retval; 84 85 for (const auto& lib : m_lib_list) 86 { 87 if (lib.file_name () == file_name) 88 { 89 retval = lib; 90 break; 91 } 92 } 93 94 return retval; 95 } 96 97 void display(void) const98 dynamic_loader::shlibs_list::display (void) const 99 { 100 std::cerr << "current shared libraries:" << std::endl; 101 for (const auto& lib : m_lib_list) 102 std::cerr << " " << lib.file_name () << std::endl; 103 } 104 105 void clear_function(const std::string & fcn_name)106 dynamic_loader::clear_function (const std::string& fcn_name) 107 { 108 warning_with_id ("Octave:reload-forces-clear", " %s", fcn_name.c_str ()); 109 110 // FIXME: is there a way to avoid this? Can we manage the list of 111 // functions that are loaded in the symbol table completely outside 112 // of the dynamic_loader class? 113 114 symbol_table& symtab = m_interpreter.get_symbol_table (); 115 116 symtab.clear_dld_function (fcn_name); 117 } 118 119 void clear(dynamic_library & oct_file)120 dynamic_loader::clear (dynamic_library& oct_file) 121 { 122 if (oct_file.number_of_functions_loaded () > 1) 123 { 124 warning_with_id ("Octave:reload-forces-clear", 125 "reloading %s clears the following functions:", 126 oct_file.file_name ().c_str ()); 127 128 std::list<std::string> removed_fcns = m_loaded_shlibs.remove (oct_file); 129 130 for (const auto& fcn_name : removed_fcns) 131 clear_function (fcn_name); 132 } 133 else 134 { 135 std::list<std::string> removed_fcns = m_loaded_shlibs.remove (oct_file); 136 137 // FIXME: is there a way to avoid this? Can we manage the list 138 // of functions that are loaded in the symbol table completely 139 // outside of the dynamic_loader class? 140 141 symbol_table& symtab = m_interpreter.get_symbol_table (); 142 143 for (const auto& fcn_name : removed_fcns) 144 symtab.clear_dld_function (fcn_name); 145 } 146 } 147 148 octave_function * load_oct(const std::string & fcn_name,const std::string & file_name,bool relative)149 dynamic_loader::load_oct (const std::string& fcn_name, 150 const std::string& file_name, 151 bool relative) 152 { 153 octave_function *retval = nullptr; 154 155 unwind_protect frame; 156 157 frame.protect_var (m_doing_load); 158 159 m_doing_load = true; 160 161 dynamic_library oct_file = m_loaded_shlibs.find_file (file_name); 162 163 if (oct_file && oct_file.is_out_of_date ()) 164 clear (oct_file); 165 166 if (! oct_file) 167 { 168 oct_file.open (file_name); 169 170 if (oct_file) 171 m_loaded_shlibs.append (oct_file); 172 } 173 174 if (! oct_file) 175 error ("%s is not a valid shared library", file_name.c_str ()); 176 177 void *function = oct_file.search (fcn_name, name_mangler); 178 179 if (! function) 180 { 181 // FIXME: can we determine this C mangling scheme 182 // automatically at run time or configure time? 183 184 function = oct_file.search (fcn_name, name_uscore_mangler); 185 } 186 187 if (function) 188 { 189 octave_dld_fcn_getter f 190 = reinterpret_cast<octave_dld_fcn_getter> (function); 191 192 retval = f (oct_file, relative); 193 194 if (! retval) 195 error ("failed to install .oct file function '%s'", 196 fcn_name.c_str ()); 197 } 198 199 return retval; 200 } 201 202 octave_function * load_mex(const std::string & fcn_name,const std::string & file_name,bool)203 dynamic_loader::load_mex (const std::string& fcn_name, 204 const std::string& file_name, 205 bool /*relative*/) 206 { 207 octave_function *retval = nullptr; 208 209 unwind_protect frame; 210 211 frame.protect_var (m_doing_load); 212 213 m_doing_load = true; 214 215 dynamic_library mex_file = m_loaded_shlibs.find_file (file_name); 216 217 if (mex_file && mex_file.is_out_of_date ()) 218 clear (mex_file); 219 220 if (! mex_file) 221 { 222 mex_file.open (file_name); 223 224 if (mex_file) 225 m_loaded_shlibs.append (mex_file); 226 } 227 228 if (! mex_file) 229 error ("%s is not a valid shared library", file_name.c_str ()); 230 231 bool have_fmex = false; 232 233 void *function = mex_file.search (fcn_name, mex_mangler); 234 235 if (! function) 236 { 237 // FIXME: Can we determine this C mangling scheme 238 // automatically at run time or configure time? 239 function = mex_file.search (fcn_name, mex_uscore_mangler); 240 241 if (! function) 242 { 243 function = mex_file.search (fcn_name, mex_f77_mangler); 244 245 if (function) 246 have_fmex = true; 247 } 248 } 249 250 if (! function) 251 error ("failed to install .mex file function '%s'", fcn_name.c_str ()); 252 253 retval = new octave_mex_function (function, have_fmex, mex_file, fcn_name); 254 255 return retval; 256 } 257 258 bool remove_oct(const std::string & fcn_name,dynamic_library & shl)259 dynamic_loader::remove_oct (const std::string& fcn_name, 260 dynamic_library& shl) 261 { 262 bool retval = false; 263 264 // We don't need to do anything if this is called because we are in 265 // the process of reloading a .oct file that has changed. 266 267 if (! m_doing_load) 268 { 269 retval = shl.remove (fcn_name); 270 271 if (shl.number_of_functions_loaded () == 0) 272 m_loaded_shlibs.remove (shl); 273 } 274 275 return retval; 276 } 277 278 bool remove_mex(const std::string & fcn_name,dynamic_library & shl)279 dynamic_loader::remove_mex (const std::string& fcn_name, 280 dynamic_library& shl) 281 { 282 // Use the same procedure as for oct files. 283 return remove_oct (fcn_name, shl); 284 } 285 286 std::string name_mangler(const std::string & name)287 dynamic_loader::name_mangler (const std::string& name) 288 { 289 return 'G' + name; 290 } 291 292 std::string name_uscore_mangler(const std::string & name)293 dynamic_loader::name_uscore_mangler (const std::string& name) 294 { 295 return "_G" + name; 296 } 297 298 std::string mex_mangler(const std::string &)299 dynamic_loader::mex_mangler (const std::string&) 300 { 301 return "mexFunction"; 302 } 303 304 std::string mex_uscore_mangler(const std::string &)305 dynamic_loader::mex_uscore_mangler (const std::string&) 306 { 307 return "_mexFunction"; 308 } 309 310 std::string mex_f77_mangler(const std::string &)311 dynamic_loader::mex_f77_mangler (const std::string&) 312 { 313 return STRINGIFY (F77_FUNC (mexfunction, MEXFUNCTION)); 314 } 315 } 316