blob: 7990111aa436c6c8dc5b3c486c3d60487c319891 [file] [log] [blame]
Chris Lattner24943d22010-06-08 16:52:24 +00001//===-- Target.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/Target/Target.h"
11
12// C Includes
13// C++ Includes
14// Other libraries and framework includes
15// Project includes
16#include "lldb/Breakpoint/BreakpointResolver.h"
17#include "lldb/Breakpoint/BreakpointResolverAddress.h"
18#include "lldb/Breakpoint/BreakpointResolverFileLine.h"
19#include "lldb/Breakpoint/BreakpointResolverName.h"
Sean Callanan77e93942010-10-29 00:29:03 +000020#include "lldb/Core/DataBufferMemoryMap.h"
Greg Clayton427f2902010-12-14 02:59:59 +000021#include "lldb/Core/Debugger.h"
Chris Lattner24943d22010-06-08 16:52:24 +000022#include "lldb/Core/Event.h"
23#include "lldb/Core/Log.h"
Chris Lattner24943d22010-06-08 16:52:24 +000024#include "lldb/Core/StreamString.h"
Greg Clayton427f2902010-12-14 02:59:59 +000025#include "lldb/Core/Timer.h"
26#include "lldb/Core/ValueObject.h"
Chris Lattner24943d22010-06-08 16:52:24 +000027#include "lldb/Host/Host.h"
28#include "lldb/lldb-private-log.h"
29#include "lldb/Symbol/ObjectFile.h"
30#include "lldb/Target/Process.h"
Greg Clayton427f2902010-12-14 02:59:59 +000031#include "lldb/Target/StackFrame.h"
Chris Lattner24943d22010-06-08 16:52:24 +000032
33using namespace lldb;
34using namespace lldb_private;
35
36//----------------------------------------------------------------------
37// Target constructor
38//----------------------------------------------------------------------
Greg Clayton63094e02010-06-23 01:19:29 +000039Target::Target(Debugger &debugger) :
Greg Clayton49ce6822010-10-31 03:01:06 +000040 Broadcaster("lldb.target"),
Greg Claytonc0c1b0c2010-11-19 03:46:01 +000041 TargetInstanceSettings (*GetSettingsController()),
Greg Clayton63094e02010-06-23 01:19:29 +000042 m_debugger (debugger),
Chris Lattner24943d22010-06-08 16:52:24 +000043 m_images(),
Greg Claytoneea26402010-09-14 23:36:40 +000044 m_section_load_list (),
Chris Lattner24943d22010-06-08 16:52:24 +000045 m_breakpoint_list (false),
46 m_internal_breakpoint_list (true),
47 m_process_sp(),
48 m_triple(),
49 m_search_filter_sp(),
50 m_image_search_paths (ImageSearchPathsChanged, this),
Greg Clayton427f2902010-12-14 02:59:59 +000051 m_scratch_ast_context_ap (NULL),
52 m_persistent_variables ()
Chris Lattner24943d22010-06-08 16:52:24 +000053{
Greg Clayton49ce6822010-10-31 03:01:06 +000054 SetEventName (eBroadcastBitBreakpointChanged, "breakpoint-changed");
55 SetEventName (eBroadcastBitModulesLoaded, "modules-loaded");
56 SetEventName (eBroadcastBitModulesUnloaded, "modules-unloaded");
57
Greg Claytone005f2c2010-11-06 01:53:30 +000058 LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));
Chris Lattner24943d22010-06-08 16:52:24 +000059 if (log)
60 log->Printf ("%p Target::Target()", this);
61}
62
63//----------------------------------------------------------------------
64// Destructor
65//----------------------------------------------------------------------
66Target::~Target()
67{
Greg Claytone005f2c2010-11-06 01:53:30 +000068 LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));
Chris Lattner24943d22010-06-08 16:52:24 +000069 if (log)
70 log->Printf ("%p Target::~Target()", this);
71 DeleteCurrentProcess ();
72}
73
74void
Caroline Tice7826c882010-10-26 03:11:13 +000075Target::Dump (Stream *s, lldb::DescriptionLevel description_level)
Chris Lattner24943d22010-06-08 16:52:24 +000076{
Greg Clayton3fed8b92010-10-08 00:21:05 +000077// s->Printf("%.*p: ", (int)sizeof(void*) * 2, this);
Caroline Tice7826c882010-10-26 03:11:13 +000078 if (description_level != lldb::eDescriptionLevelBrief)
79 {
80 s->Indent();
81 s->PutCString("Target\n");
82 s->IndentMore();
Greg Clayton3f5ee7f2010-10-29 04:59:35 +000083 m_images.Dump(s);
84 m_breakpoint_list.Dump(s);
85 m_internal_breakpoint_list.Dump(s);
86 s->IndentLess();
Caroline Tice7826c882010-10-26 03:11:13 +000087 }
88 else
89 {
Greg Claytona66ba462010-10-30 04:51:46 +000090 s->PutCString (GetExecutableModule()->GetFileSpec().GetFilename().GetCString());
Caroline Tice7826c882010-10-26 03:11:13 +000091 }
Chris Lattner24943d22010-06-08 16:52:24 +000092}
93
94void
95Target::DeleteCurrentProcess ()
96{
97 if (m_process_sp.get())
98 {
Greg Clayton49480b12010-09-14 23:52:43 +000099 m_section_load_list.Clear();
Chris Lattner24943d22010-06-08 16:52:24 +0000100 if (m_process_sp->IsAlive())
101 m_process_sp->Destroy();
102 else
103 m_process_sp->Finalize();
104
105 // Do any cleanup of the target we need to do between process instances.
106 // NB It is better to do this before destroying the process in case the
107 // clean up needs some help from the process.
108 m_breakpoint_list.ClearAllBreakpointSites();
109 m_internal_breakpoint_list.ClearAllBreakpointSites();
110 m_process_sp.reset();
111 }
112}
113
114const lldb::ProcessSP &
115Target::CreateProcess (Listener &listener, const char *plugin_name)
116{
117 DeleteCurrentProcess ();
118 m_process_sp.reset(Process::FindPlugin(*this, plugin_name, listener));
119 return m_process_sp;
120}
121
122const lldb::ProcessSP &
123Target::GetProcessSP () const
124{
125 return m_process_sp;
126}
127
128lldb::TargetSP
129Target::GetSP()
130{
Greg Clayton63094e02010-06-23 01:19:29 +0000131 return m_debugger.GetTargetList().GetTargetSP(this);
Chris Lattner24943d22010-06-08 16:52:24 +0000132}
133
134BreakpointList &
135Target::GetBreakpointList(bool internal)
136{
137 if (internal)
138 return m_internal_breakpoint_list;
139 else
140 return m_breakpoint_list;
141}
142
143const BreakpointList &
144Target::GetBreakpointList(bool internal) const
145{
146 if (internal)
147 return m_internal_breakpoint_list;
148 else
149 return m_breakpoint_list;
150}
151
152BreakpointSP
153Target::GetBreakpointByID (break_id_t break_id)
154{
155 BreakpointSP bp_sp;
156
157 if (LLDB_BREAK_ID_IS_INTERNAL (break_id))
158 bp_sp = m_internal_breakpoint_list.FindBreakpointByID (break_id);
159 else
160 bp_sp = m_breakpoint_list.FindBreakpointByID (break_id);
161
162 return bp_sp;
163}
164
165BreakpointSP
166Target::CreateBreakpoint (const FileSpec *containingModule, const FileSpec &file, uint32_t line_no, bool check_inlines, bool internal)
167{
168 SearchFilterSP filter_sp(GetSearchFilterForModule (containingModule));
169 BreakpointResolverSP resolver_sp(new BreakpointResolverFileLine (NULL, file, line_no, check_inlines));
170 return CreateBreakpoint (filter_sp, resolver_sp, internal);
171}
172
173
174BreakpointSP
Greg Clayton33ed1702010-08-24 00:45:41 +0000175Target::CreateBreakpoint (lldb::addr_t addr, bool internal)
Chris Lattner24943d22010-06-08 16:52:24 +0000176{
Chris Lattner24943d22010-06-08 16:52:24 +0000177 Address so_addr;
178 // Attempt to resolve our load address if possible, though it is ok if
179 // it doesn't resolve to section/offset.
180
Greg Clayton33ed1702010-08-24 00:45:41 +0000181 // Try and resolve as a load address if possible
Greg Claytoneea26402010-09-14 23:36:40 +0000182 m_section_load_list.ResolveLoadAddress(addr, so_addr);
Greg Clayton33ed1702010-08-24 00:45:41 +0000183 if (!so_addr.IsValid())
184 {
185 // The address didn't resolve, so just set this as an absolute address
186 so_addr.SetOffset (addr);
187 }
188 BreakpointSP bp_sp (CreateBreakpoint(so_addr, internal));
Chris Lattner24943d22010-06-08 16:52:24 +0000189 return bp_sp;
190}
191
192BreakpointSP
193Target::CreateBreakpoint (Address &addr, bool internal)
194{
195 TargetSP target_sp = this->GetSP();
196 SearchFilterSP filter_sp(new SearchFilter (target_sp));
197 BreakpointResolverSP resolver_sp (new BreakpointResolverAddress (NULL, addr));
198 return CreateBreakpoint (filter_sp, resolver_sp, internal);
199}
200
201BreakpointSP
Greg Clayton12bec712010-06-28 21:30:43 +0000202Target::CreateBreakpoint (FileSpec *containingModule, const char *func_name, uint32_t func_name_type_mask, bool internal)
Chris Lattner24943d22010-06-08 16:52:24 +0000203{
Greg Clayton12bec712010-06-28 21:30:43 +0000204 BreakpointSP bp_sp;
205 if (func_name)
206 {
207 SearchFilterSP filter_sp(GetSearchFilterForModule (containingModule));
208 BreakpointResolverSP resolver_sp (new BreakpointResolverName (NULL, func_name, func_name_type_mask, Breakpoint::Exact));
209 bp_sp = CreateBreakpoint (filter_sp, resolver_sp, internal);
210 }
211 return bp_sp;
Chris Lattner24943d22010-06-08 16:52:24 +0000212}
213
214
215SearchFilterSP
216Target::GetSearchFilterForModule (const FileSpec *containingModule)
217{
218 SearchFilterSP filter_sp;
219 lldb::TargetSP target_sp = this->GetSP();
220 if (containingModule != NULL)
221 {
222 // TODO: We should look into sharing module based search filters
223 // across many breakpoints like we do for the simple target based one
224 filter_sp.reset (new SearchFilterByModule (target_sp, *containingModule));
225 }
226 else
227 {
228 if (m_search_filter_sp.get() == NULL)
229 m_search_filter_sp.reset (new SearchFilter (target_sp));
230 filter_sp = m_search_filter_sp;
231 }
232 return filter_sp;
233}
234
235BreakpointSP
236Target::CreateBreakpoint (FileSpec *containingModule, RegularExpression &func_regex, bool internal)
237{
238 SearchFilterSP filter_sp(GetSearchFilterForModule (containingModule));
239 BreakpointResolverSP resolver_sp(new BreakpointResolverName (NULL, func_regex));
240
241 return CreateBreakpoint (filter_sp, resolver_sp, internal);
242}
243
244BreakpointSP
245Target::CreateBreakpoint (SearchFilterSP &filter_sp, BreakpointResolverSP &resolver_sp, bool internal)
246{
247 BreakpointSP bp_sp;
248 if (filter_sp && resolver_sp)
249 {
250 bp_sp.reset(new Breakpoint (*this, filter_sp, resolver_sp));
251 resolver_sp->SetBreakpoint (bp_sp.get());
252
253 if (internal)
Greg Claytonc7f5d5c2010-07-23 23:33:17 +0000254 m_internal_breakpoint_list.Add (bp_sp, false);
Chris Lattner24943d22010-06-08 16:52:24 +0000255 else
Greg Claytonc7f5d5c2010-07-23 23:33:17 +0000256 m_breakpoint_list.Add (bp_sp, true);
Chris Lattner24943d22010-06-08 16:52:24 +0000257
Greg Claytone005f2c2010-11-06 01:53:30 +0000258 LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
Chris Lattner24943d22010-06-08 16:52:24 +0000259 if (log)
260 {
261 StreamString s;
262 bp_sp->GetDescription(&s, lldb::eDescriptionLevelVerbose);
263 log->Printf ("Target::%s (internal = %s) => break_id = %s\n", __FUNCTION__, internal ? "yes" : "no", s.GetData());
264 }
265
Chris Lattner24943d22010-06-08 16:52:24 +0000266 bp_sp->ResolveBreakpoint();
267 }
Jim Inghamd1686902010-10-14 23:45:03 +0000268
269 if (!internal && bp_sp)
270 {
271 m_last_created_breakpoint = bp_sp;
272 }
273
Chris Lattner24943d22010-06-08 16:52:24 +0000274 return bp_sp;
275}
276
277void
278Target::RemoveAllBreakpoints (bool internal_also)
279{
Greg Claytone005f2c2010-11-06 01:53:30 +0000280 LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
Chris Lattner24943d22010-06-08 16:52:24 +0000281 if (log)
282 log->Printf ("Target::%s (internal_also = %s)\n", __FUNCTION__, internal_also ? "yes" : "no");
283
Greg Claytonc7f5d5c2010-07-23 23:33:17 +0000284 m_breakpoint_list.RemoveAll (true);
Chris Lattner24943d22010-06-08 16:52:24 +0000285 if (internal_also)
Greg Claytonc7f5d5c2010-07-23 23:33:17 +0000286 m_internal_breakpoint_list.RemoveAll (false);
Jim Inghamd1686902010-10-14 23:45:03 +0000287
288 m_last_created_breakpoint.reset();
Chris Lattner24943d22010-06-08 16:52:24 +0000289}
290
291void
292Target::DisableAllBreakpoints (bool internal_also)
293{
Greg Claytone005f2c2010-11-06 01:53:30 +0000294 LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
Chris Lattner24943d22010-06-08 16:52:24 +0000295 if (log)
296 log->Printf ("Target::%s (internal_also = %s)\n", __FUNCTION__, internal_also ? "yes" : "no");
297
298 m_breakpoint_list.SetEnabledAll (false);
299 if (internal_also)
300 m_internal_breakpoint_list.SetEnabledAll (false);
301}
302
303void
304Target::EnableAllBreakpoints (bool internal_also)
305{
Greg Claytone005f2c2010-11-06 01:53:30 +0000306 LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
Chris Lattner24943d22010-06-08 16:52:24 +0000307 if (log)
308 log->Printf ("Target::%s (internal_also = %s)\n", __FUNCTION__, internal_also ? "yes" : "no");
309
310 m_breakpoint_list.SetEnabledAll (true);
311 if (internal_also)
312 m_internal_breakpoint_list.SetEnabledAll (true);
313}
314
315bool
316Target::RemoveBreakpointByID (break_id_t break_id)
317{
Greg Claytone005f2c2010-11-06 01:53:30 +0000318 LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
Chris Lattner24943d22010-06-08 16:52:24 +0000319 if (log)
320 log->Printf ("Target::%s (break_id = %i, internal = %s)\n", __FUNCTION__, break_id, LLDB_BREAK_ID_IS_INTERNAL (break_id) ? "yes" : "no");
321
322 if (DisableBreakpointByID (break_id))
323 {
324 if (LLDB_BREAK_ID_IS_INTERNAL (break_id))
Greg Claytonc7f5d5c2010-07-23 23:33:17 +0000325 m_internal_breakpoint_list.Remove(break_id, false);
Chris Lattner24943d22010-06-08 16:52:24 +0000326 else
Jim Inghamd1686902010-10-14 23:45:03 +0000327 {
328 if (m_last_created_breakpoint->GetID() == break_id)
329 m_last_created_breakpoint.reset();
Greg Claytonc7f5d5c2010-07-23 23:33:17 +0000330 m_breakpoint_list.Remove(break_id, true);
Jim Inghamd1686902010-10-14 23:45:03 +0000331 }
Chris Lattner24943d22010-06-08 16:52:24 +0000332 return true;
333 }
334 return false;
335}
336
337bool
338Target::DisableBreakpointByID (break_id_t break_id)
339{
Greg Claytone005f2c2010-11-06 01:53:30 +0000340 LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
Chris Lattner24943d22010-06-08 16:52:24 +0000341 if (log)
342 log->Printf ("Target::%s (break_id = %i, internal = %s)\n", __FUNCTION__, break_id, LLDB_BREAK_ID_IS_INTERNAL (break_id) ? "yes" : "no");
343
344 BreakpointSP bp_sp;
345
346 if (LLDB_BREAK_ID_IS_INTERNAL (break_id))
347 bp_sp = m_internal_breakpoint_list.FindBreakpointByID (break_id);
348 else
349 bp_sp = m_breakpoint_list.FindBreakpointByID (break_id);
350 if (bp_sp)
351 {
352 bp_sp->SetEnabled (false);
353 return true;
354 }
355 return false;
356}
357
358bool
359Target::EnableBreakpointByID (break_id_t break_id)
360{
Greg Claytone005f2c2010-11-06 01:53:30 +0000361 LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
Chris Lattner24943d22010-06-08 16:52:24 +0000362 if (log)
363 log->Printf ("Target::%s (break_id = %i, internal = %s)\n",
364 __FUNCTION__,
365 break_id,
366 LLDB_BREAK_ID_IS_INTERNAL (break_id) ? "yes" : "no");
367
368 BreakpointSP bp_sp;
369
370 if (LLDB_BREAK_ID_IS_INTERNAL (break_id))
371 bp_sp = m_internal_breakpoint_list.FindBreakpointByID (break_id);
372 else
373 bp_sp = m_breakpoint_list.FindBreakpointByID (break_id);
374
375 if (bp_sp)
376 {
377 bp_sp->SetEnabled (true);
378 return true;
379 }
380 return false;
381}
382
383ModuleSP
384Target::GetExecutableModule ()
385{
386 ModuleSP executable_sp;
387 if (m_images.GetSize() > 0)
388 executable_sp = m_images.GetModuleAtIndex(0);
389 return executable_sp;
390}
391
392void
393Target::SetExecutableModule (ModuleSP& executable_sp, bool get_dependent_files)
394{
395 m_images.Clear();
396 m_scratch_ast_context_ap.reset();
397
398 if (executable_sp.get())
399 {
400 Timer scoped_timer (__PRETTY_FUNCTION__,
401 "Target::SetExecutableModule (executable = '%s/%s')",
402 executable_sp->GetFileSpec().GetDirectory().AsCString(),
403 executable_sp->GetFileSpec().GetFilename().AsCString());
404
405 m_images.Append(executable_sp); // The first image is our exectuable file
406
407 ArchSpec exe_arch = executable_sp->GetArchitecture();
Jim Ingham7508e732010-08-09 23:31:02 +0000408 // If we haven't set an architecture yet, reset our architecture based on what we found in the executable module.
409 if (!m_arch_spec.IsValid())
410 m_arch_spec = exe_arch;
411
Chris Lattner24943d22010-06-08 16:52:24 +0000412 FileSpecList dependent_files;
413 ObjectFile * executable_objfile = executable_sp->GetObjectFile();
414 if (executable_objfile == NULL)
415 {
416
417 FileSpec bundle_executable(executable_sp->GetFileSpec());
Greg Clayton24b48ff2010-10-17 22:03:32 +0000418 if (Host::ResolveExecutableInBundle (bundle_executable))
Chris Lattner24943d22010-06-08 16:52:24 +0000419 {
420 ModuleSP bundle_exe_module_sp(GetSharedModule(bundle_executable,
421 exe_arch));
422 SetExecutableModule (bundle_exe_module_sp, get_dependent_files);
423 if (bundle_exe_module_sp->GetObjectFile() != NULL)
424 executable_sp = bundle_exe_module_sp;
425 return;
426 }
427 }
428
429 if (executable_objfile)
430 {
431 executable_objfile->GetDependentModules(dependent_files);
432 for (uint32_t i=0; i<dependent_files.GetSize(); i++)
433 {
434 ModuleSP image_module_sp(GetSharedModule(dependent_files.GetFileSpecPointerAtIndex(i),
435 exe_arch));
436 if (image_module_sp.get())
437 {
438 //image_module_sp->Dump(&s);// REMOVE THIS, DEBUG ONLY
439 ObjectFile *objfile = image_module_sp->GetObjectFile();
440 if (objfile)
441 objfile->GetDependentModules(dependent_files);
442 }
443 }
444 }
445
446 // Now see if we know the target triple, and if so, create our scratch AST context:
447 ConstString target_triple;
448 if (GetTargetTriple(target_triple))
449 {
450 m_scratch_ast_context_ap.reset (new ClangASTContext(target_triple.GetCString()));
451 }
452 }
Caroline Tice1ebef442010-09-27 00:30:10 +0000453
454 UpdateInstanceName();
Chris Lattner24943d22010-06-08 16:52:24 +0000455}
456
457
458ModuleList&
459Target::GetImages ()
460{
461 return m_images;
462}
463
464ArchSpec
465Target::GetArchitecture () const
466{
Jim Ingham7508e732010-08-09 23:31:02 +0000467 return m_arch_spec;
Chris Lattner24943d22010-06-08 16:52:24 +0000468}
469
Jim Ingham7508e732010-08-09 23:31:02 +0000470bool
471Target::SetArchitecture (const ArchSpec &arch_spec)
472{
473 if (m_arch_spec == arch_spec)
474 {
475 // If we're setting the architecture to our current architecture, we
476 // don't need to do anything.
477 return true;
478 }
479 else if (!m_arch_spec.IsValid())
480 {
481 // If we haven't got a valid arch spec, then we just need to set it.
482 m_arch_spec = arch_spec;
483 return true;
484 }
485 else
486 {
487 // If we have an executable file, try to reset the executable to the desired architecture
488 m_arch_spec = arch_spec;
489 ModuleSP executable_sp = GetExecutableModule ();
490 m_images.Clear();
491 m_scratch_ast_context_ap.reset();
492 m_triple.Clear();
493 // Need to do something about unsetting breakpoints.
494
495 if (executable_sp)
496 {
497 FileSpec exec_file_spec = executable_sp->GetFileSpec();
498 Error error = ModuleList::GetSharedModule(exec_file_spec,
499 arch_spec,
500 NULL,
501 NULL,
502 0,
503 executable_sp,
504 NULL,
505 NULL);
506
507 if (!error.Fail() && executable_sp)
508 {
509 SetExecutableModule (executable_sp, true);
510 return true;
511 }
512 else
513 {
514 return false;
515 }
516 }
517 else
518 {
519 return false;
520 }
521 }
522}
Chris Lattner24943d22010-06-08 16:52:24 +0000523
524bool
525Target::GetTargetTriple(ConstString &triple)
526{
527 triple.Clear();
528
529 if (m_triple)
530 {
531 triple = m_triple;
532 }
533 else
534 {
535 Module *exe_module = GetExecutableModule().get();
536 if (exe_module)
537 {
538 ObjectFile *objfile = exe_module->GetObjectFile();
539 if (objfile)
540 {
541 objfile->GetTargetTriple(m_triple);
542 triple = m_triple;
543 }
544 }
545 }
546 return !triple.IsEmpty();
547}
548
549void
550Target::ModuleAdded (ModuleSP &module_sp)
551{
552 // A module is being added to this target for the first time
553 ModuleList module_list;
554 module_list.Append(module_sp);
555 ModulesDidLoad (module_list);
556}
557
558void
559Target::ModuleUpdated (ModuleSP &old_module_sp, ModuleSP &new_module_sp)
560{
561 // A module is being added to this target for the first time
562 ModuleList module_list;
563 module_list.Append (old_module_sp);
564 ModulesDidUnload (module_list);
565 module_list.Clear ();
566 module_list.Append (new_module_sp);
567 ModulesDidLoad (module_list);
568}
569
570void
571Target::ModulesDidLoad (ModuleList &module_list)
572{
573 m_breakpoint_list.UpdateBreakpoints (module_list, true);
574 // TODO: make event data that packages up the module_list
575 BroadcastEvent (eBroadcastBitModulesLoaded, NULL);
576}
577
578void
579Target::ModulesDidUnload (ModuleList &module_list)
580{
581 m_breakpoint_list.UpdateBreakpoints (module_list, false);
Greg Clayton7b9fcc02010-12-06 23:51:26 +0000582
583 // Remove the images from the target image list
584 m_images.Remove(module_list);
585
Chris Lattner24943d22010-06-08 16:52:24 +0000586 // TODO: make event data that packages up the module_list
587 BroadcastEvent (eBroadcastBitModulesUnloaded, NULL);
588}
589
590size_t
Greg Clayton2cf6e9e2010-06-30 23:04:24 +0000591Target::ReadMemory (const Address& addr, void *dst, size_t dst_len, Error &error)
Chris Lattner24943d22010-06-08 16:52:24 +0000592{
Chris Lattner24943d22010-06-08 16:52:24 +0000593 error.Clear();
Chris Lattner24943d22010-06-08 16:52:24 +0000594
Greg Clayton70436352010-06-30 23:03:03 +0000595 bool process_is_valid = m_process_sp && m_process_sp->IsAlive();
596
597 Address resolved_addr(addr);
598 if (!resolved_addr.IsSectionOffset())
599 {
600 if (process_is_valid)
Chris Lattner24943d22010-06-08 16:52:24 +0000601 {
Greg Claytoneea26402010-09-14 23:36:40 +0000602 m_section_load_list.ResolveLoadAddress (addr.GetOffset(), resolved_addr);
Greg Clayton70436352010-06-30 23:03:03 +0000603 }
604 else
605 {
606 m_images.ResolveFileAddress(addr.GetOffset(), resolved_addr);
607 }
608 }
609
610
611 if (process_is_valid)
612 {
Greg Claytoneea26402010-09-14 23:36:40 +0000613 lldb::addr_t load_addr = resolved_addr.GetLoadAddress (this);
Greg Clayton70436352010-06-30 23:03:03 +0000614 if (load_addr == LLDB_INVALID_ADDRESS)
615 {
616 if (resolved_addr.GetModule() && resolved_addr.GetModule()->GetFileSpec())
617 error.SetErrorStringWithFormat("%s[0x%llx] can't be resolved, %s in not currently loaded.\n",
618 resolved_addr.GetModule()->GetFileSpec().GetFilename().AsCString(),
619 resolved_addr.GetFileAddress());
620 else
621 error.SetErrorStringWithFormat("0x%llx can't be resolved.\n", resolved_addr.GetFileAddress());
622 }
623 else
624 {
625 size_t bytes_read = m_process_sp->ReadMemory(load_addr, dst, dst_len, error);
Chris Lattner24943d22010-06-08 16:52:24 +0000626 if (bytes_read != dst_len)
627 {
628 if (error.Success())
629 {
630 if (bytes_read == 0)
Greg Clayton70436352010-06-30 23:03:03 +0000631 error.SetErrorStringWithFormat("Read memory from 0x%llx failed.\n", load_addr);
Chris Lattner24943d22010-06-08 16:52:24 +0000632 else
Greg Clayton70436352010-06-30 23:03:03 +0000633 error.SetErrorStringWithFormat("Only %zu of %zu bytes were read from memory at 0x%llx.\n", bytes_read, dst_len, load_addr);
Chris Lattner24943d22010-06-08 16:52:24 +0000634 }
635 }
Greg Clayton70436352010-06-30 23:03:03 +0000636 if (bytes_read)
637 return bytes_read;
638 // If the address is not section offset we have an address that
639 // doesn't resolve to any address in any currently loaded shared
640 // libaries and we failed to read memory so there isn't anything
641 // more we can do. If it is section offset, we might be able to
642 // read cached memory from the object file.
643 if (!resolved_addr.IsSectionOffset())
644 return 0;
Chris Lattner24943d22010-06-08 16:52:24 +0000645 }
Chris Lattner24943d22010-06-08 16:52:24 +0000646 }
Greg Clayton70436352010-06-30 23:03:03 +0000647
648 const Section *section = resolved_addr.GetSection();
649 if (section && section->GetModule())
650 {
651 ObjectFile *objfile = section->GetModule()->GetObjectFile();
652 return section->ReadSectionDataFromObjectFile (objfile,
653 resolved_addr.GetOffset(),
654 dst,
655 dst_len);
656 }
657 return 0;
Chris Lattner24943d22010-06-08 16:52:24 +0000658}
659
660
661ModuleSP
662Target::GetSharedModule
663(
664 const FileSpec& file_spec,
665 const ArchSpec& arch,
666 const UUID *uuid_ptr,
667 const ConstString *object_name,
668 off_t object_offset,
669 Error *error_ptr
670)
671{
672 // Don't pass in the UUID so we can tell if we have a stale value in our list
673 ModuleSP old_module_sp; // This will get filled in if we have a new version of the library
674 bool did_create_module = false;
675 ModuleSP module_sp;
676
677 // If there are image search path entries, try to use them first to acquire a suitable image.
678
679 Error error;
680
681 if (m_image_search_paths.GetSize())
682 {
683 FileSpec transformed_spec;
684 if (m_image_search_paths.RemapPath (file_spec.GetDirectory(), transformed_spec.GetDirectory()))
685 {
686 transformed_spec.GetFilename() = file_spec.GetFilename();
687 error = ModuleList::GetSharedModule (transformed_spec, arch, uuid_ptr, object_name, object_offset, module_sp, &old_module_sp, &did_create_module);
688 }
689 }
690
691 // If a module hasn't been found yet, use the unmodified path.
692
693 if (!module_sp)
694 {
695 error = (ModuleList::GetSharedModule (file_spec, arch, uuid_ptr, object_name, object_offset, module_sp, &old_module_sp, &did_create_module));
696 }
697
698 if (module_sp)
699 {
700 m_images.Append (module_sp);
701 if (did_create_module)
702 {
703 if (old_module_sp && m_images.GetIndexForModule (old_module_sp.get()) != LLDB_INVALID_INDEX32)
704 ModuleUpdated(old_module_sp, module_sp);
705 else
706 ModuleAdded(module_sp);
707 }
708 }
709 if (error_ptr)
710 *error_ptr = error;
711 return module_sp;
712}
713
714
715Target *
716Target::CalculateTarget ()
717{
718 return this;
719}
720
721Process *
722Target::CalculateProcess ()
723{
724 return NULL;
725}
726
727Thread *
728Target::CalculateThread ()
729{
730 return NULL;
731}
732
733StackFrame *
734Target::CalculateStackFrame ()
735{
736 return NULL;
737}
738
739void
Greg Claytona830adb2010-10-04 01:05:56 +0000740Target::CalculateExecutionContext (ExecutionContext &exe_ctx)
Chris Lattner24943d22010-06-08 16:52:24 +0000741{
742 exe_ctx.target = this;
743 exe_ctx.process = NULL; // Do NOT fill in process...
744 exe_ctx.thread = NULL;
745 exe_ctx.frame = NULL;
746}
747
748PathMappingList &
749Target::GetImageSearchPathList ()
750{
751 return m_image_search_paths;
752}
753
754void
755Target::ImageSearchPathsChanged
756(
757 const PathMappingList &path_list,
758 void *baton
759)
760{
761 Target *target = (Target *)baton;
762 if (target->m_images.GetSize() > 1)
763 {
764 ModuleSP exe_module_sp (target->GetExecutableModule());
765 if (exe_module_sp)
766 {
767 target->m_images.Clear();
768 target->SetExecutableModule (exe_module_sp, true);
769 }
770 }
771}
772
773ClangASTContext *
774Target::GetScratchClangASTContext()
775{
776 return m_scratch_ast_context_ap.get();
777}
Caroline Tice5bc8c972010-09-20 20:44:43 +0000778
Greg Clayton990de7b2010-11-18 23:32:35 +0000779void
780Target::Initialize ()
Caroline Tice5bc8c972010-09-20 20:44:43 +0000781{
Greg Clayton990de7b2010-11-18 23:32:35 +0000782 UserSettingsControllerSP &usc = GetSettingsController();
783 usc.reset (new SettingsController);
784 UserSettingsController::InitializeSettingsController (usc,
785 SettingsController::global_settings_table,
786 SettingsController::instance_settings_table);
787}
Caroline Tice5bc8c972010-09-20 20:44:43 +0000788
Greg Clayton990de7b2010-11-18 23:32:35 +0000789void
790Target::Terminate ()
791{
792 UserSettingsControllerSP &usc = GetSettingsController();
793 UserSettingsController::FinalizeSettingsController (usc);
794 usc.reset();
795}
Caroline Tice5bc8c972010-09-20 20:44:43 +0000796
Greg Clayton990de7b2010-11-18 23:32:35 +0000797UserSettingsControllerSP &
798Target::GetSettingsController ()
799{
800 static UserSettingsControllerSP g_settings_controller;
Caroline Tice5bc8c972010-09-20 20:44:43 +0000801 return g_settings_controller;
802}
803
804ArchSpec
805Target::GetDefaultArchitecture ()
806{
Greg Claytonc0c1b0c2010-11-19 03:46:01 +0000807 lldb::UserSettingsControllerSP &settings_controller = GetSettingsController();
Caroline Tice5bc8c972010-09-20 20:44:43 +0000808 lldb::SettableVariableType var_type;
809 Error err;
810 StringList result = settings_controller->GetVariable ("target.default-arch", var_type, "[]", err);
811
812 const char *default_name = "";
813 if (result.GetSize() == 1 && err.Success())
814 default_name = result.GetStringAtIndex (0);
815
816 ArchSpec default_arch (default_name);
817 return default_arch;
818}
819
820void
821Target::SetDefaultArchitecture (ArchSpec new_arch)
822{
823 if (new_arch.IsValid())
Greg Claytonc0c1b0c2010-11-19 03:46:01 +0000824 GetSettingsController ()->SetVariable ("target.default-arch",
825 new_arch.AsCString(),
826 lldb::eVarSetOperationAssign,
827 false,
828 "[]");
Caroline Tice5bc8c972010-09-20 20:44:43 +0000829}
830
Greg Claytona830adb2010-10-04 01:05:56 +0000831Target *
832Target::GetTargetFromContexts (const ExecutionContext *exe_ctx_ptr, const SymbolContext *sc_ptr)
833{
834 // The target can either exist in the "process" of ExecutionContext, or in
835 // the "target_sp" member of SymbolContext. This accessor helper function
836 // will get the target from one of these locations.
837
838 Target *target = NULL;
839 if (sc_ptr != NULL)
840 target = sc_ptr->target_sp.get();
841 if (target == NULL)
842 {
843 if (exe_ctx_ptr != NULL && exe_ctx_ptr->process != NULL)
844 target = &exe_ctx_ptr->process->GetTarget();
845 }
846 return target;
847}
848
849
Caroline Tice1ebef442010-09-27 00:30:10 +0000850void
851Target::UpdateInstanceName ()
852{
853 StreamString sstr;
854
855 ModuleSP module_sp = GetExecutableModule();
856 if (module_sp)
857 {
Greg Claytonbf6e2102010-10-27 02:06:37 +0000858 sstr.Printf ("%s_%s",
859 module_sp->GetFileSpec().GetFilename().AsCString(),
Caroline Tice1ebef442010-09-27 00:30:10 +0000860 module_sp->GetArchitecture().AsCString());
Greg Claytonc0c1b0c2010-11-19 03:46:01 +0000861 GetSettingsController()->RenameInstanceSettings (GetInstanceName().AsCString(),
862 sstr.GetData());
Caroline Tice1ebef442010-09-27 00:30:10 +0000863 }
864}
865
Sean Callanan77e93942010-10-29 00:29:03 +0000866const char *
867Target::GetExpressionPrefixContentsAsCString ()
868{
869 return m_expr_prefix_contents.c_str();
870}
871
Greg Clayton427f2902010-12-14 02:59:59 +0000872ExecutionResults
873Target::EvaluateExpression
874(
875 const char *expr_cstr,
876 StackFrame *frame,
877 bool unwind_on_error,
878 lldb::ValueObjectSP &result_valobj_sp
879)
880{
881 ExecutionResults execution_results = eExecutionSetupError;
882
883 result_valobj_sp.reset();
884
885 ExecutionContext exe_ctx;
886 if (frame)
887 {
888 frame->CalculateExecutionContext(exe_ctx);
Greg Claytonc3b61d22010-12-15 05:08:08 +0000889 Error error;
890 const bool check_ptr_vs_member = true;
891 result_valobj_sp = frame->GetValueForVariableExpressionPath (expr_cstr, check_ptr_vs_member, error);
Greg Clayton427f2902010-12-14 02:59:59 +0000892 }
893 else if (m_process_sp)
894 {
895 m_process_sp->CalculateExecutionContext(exe_ctx);
896 }
897 else
898 {
899 CalculateExecutionContext(exe_ctx);
900 }
901
902 if (result_valobj_sp)
903 {
904 execution_results = eExecutionCompleted;
905 // We got a result from the frame variable expression path above...
906 ConstString persistent_variable_name (m_persistent_variables.GetNextPersistentVariableName());
907
908 lldb::ValueObjectSP const_valobj_sp;
909
910 // Check in case our value is already a constant value
911 if (result_valobj_sp->GetIsConstant())
912 {
913 const_valobj_sp = result_valobj_sp;
914 const_valobj_sp->SetName (persistent_variable_name);
915 }
916 else
917 const_valobj_sp = result_valobj_sp->CreateConstantValue (exe_ctx.GetBestExecutionContextScope(),
918 persistent_variable_name);
919
920 result_valobj_sp = const_valobj_sp;
921
922 ClangExpressionVariableSP clang_expr_variable_sp(m_persistent_variables.CreatePersistentVariable(result_valobj_sp));
923 assert (clang_expr_variable_sp.get());
924 }
925 else
926 {
927 // Make sure we aren't just trying to see the value of a persistent
928 // variable (something like "$0")
929 lldb::ClangExpressionVariableSP persistent_var_sp (m_persistent_variables.GetVariable (expr_cstr));
930 if (persistent_var_sp)
931 {
932 result_valobj_sp = persistent_var_sp->GetValueObject ();
933 execution_results = eExecutionCompleted;
934 }
935 else
936 {
937 const char *prefix = GetExpressionPrefixContentsAsCString();
938
939 execution_results = ClangUserExpression::Evaluate (exe_ctx,
940 unwind_on_error,
941 expr_cstr,
942 prefix,
943 result_valobj_sp);
944 }
945 }
946 return execution_results;
947}
948
Caroline Tice5bc8c972010-09-20 20:44:43 +0000949//--------------------------------------------------------------
950// class Target::SettingsController
951//--------------------------------------------------------------
952
953Target::SettingsController::SettingsController () :
954 UserSettingsController ("target", Debugger::GetSettingsController()),
955 m_default_architecture ()
956{
957 m_default_settings.reset (new TargetInstanceSettings (*this, false,
958 InstanceSettings::GetDefaultName().AsCString()));
959}
960
961Target::SettingsController::~SettingsController ()
962{
963}
964
965lldb::InstanceSettingsSP
966Target::SettingsController::CreateInstanceSettings (const char *instance_name)
967{
Greg Claytonc0c1b0c2010-11-19 03:46:01 +0000968 TargetInstanceSettings *new_settings = new TargetInstanceSettings (*GetSettingsController(),
969 false,
970 instance_name);
Caroline Tice5bc8c972010-09-20 20:44:43 +0000971 lldb::InstanceSettingsSP new_settings_sp (new_settings);
972 return new_settings_sp;
973}
974
975const ConstString &
976Target::SettingsController::DefArchVarName ()
977{
978 static ConstString def_arch_var_name ("default-arch");
979
980 return def_arch_var_name;
981}
982
983bool
984Target::SettingsController::SetGlobalVariable (const ConstString &var_name,
985 const char *index_value,
986 const char *value,
987 const SettingEntry &entry,
988 const lldb::VarSetOperationType op,
989 Error&err)
990{
991 if (var_name == DefArchVarName())
992 {
993 ArchSpec tmp_spec (value);
994 if (tmp_spec.IsValid())
995 m_default_architecture = tmp_spec;
996 else
997 err.SetErrorStringWithFormat ("'%s' is not a valid architecture.", value);
998 }
999 return true;
1000}
1001
1002
1003bool
1004Target::SettingsController::GetGlobalVariable (const ConstString &var_name,
1005 StringList &value,
1006 Error &err)
1007{
1008 if (var_name == DefArchVarName())
1009 {
Greg Claytonbf6e2102010-10-27 02:06:37 +00001010 // If the arch is invalid (the default), don't show a string for it
1011 if (m_default_architecture.IsValid())
1012 value.AppendString (m_default_architecture.AsCString());
Caroline Tice5bc8c972010-09-20 20:44:43 +00001013 return true;
1014 }
1015 else
1016 err.SetErrorStringWithFormat ("unrecognized variable name '%s'", var_name.AsCString());
1017
1018 return false;
1019}
1020
1021//--------------------------------------------------------------
1022// class TargetInstanceSettings
1023//--------------------------------------------------------------
1024
Greg Clayton638351a2010-12-04 00:10:17 +00001025TargetInstanceSettings::TargetInstanceSettings
1026(
1027 UserSettingsController &owner,
1028 bool live_instance,
1029 const char *name
1030) :
1031 InstanceSettings (owner, name ? name : InstanceSettings::InvalidName().AsCString(), live_instance)
Caroline Tice5bc8c972010-09-20 20:44:43 +00001032{
1033 // CopyInstanceSettings is a pure virtual function in InstanceSettings; it therefore cannot be called
1034 // until the vtables for TargetInstanceSettings are properly set up, i.e. AFTER all the initializers.
1035 // For this reason it has to be called here, rather than in the initializer or in the parent constructor.
1036 // This is true for CreateInstanceName() too.
1037
1038 if (GetInstanceName () == InstanceSettings::InvalidName())
1039 {
1040 ChangeInstanceName (std::string (CreateInstanceName().AsCString()));
1041 m_owner.RegisterInstanceSettings (this);
1042 }
1043
1044 if (live_instance)
1045 {
1046 const lldb::InstanceSettingsSP &pending_settings = m_owner.FindPendingSettings (m_instance_name);
1047 CopyInstanceSettings (pending_settings,false);
1048 //m_owner.RemovePendingSettings (m_instance_name);
1049 }
1050}
1051
1052TargetInstanceSettings::TargetInstanceSettings (const TargetInstanceSettings &rhs) :
Greg Claytonc0c1b0c2010-11-19 03:46:01 +00001053 InstanceSettings (*Target::GetSettingsController(), CreateInstanceName().AsCString())
Caroline Tice5bc8c972010-09-20 20:44:43 +00001054{
1055 if (m_instance_name != InstanceSettings::GetDefaultName())
1056 {
1057 const lldb::InstanceSettingsSP &pending_settings = m_owner.FindPendingSettings (m_instance_name);
1058 CopyInstanceSettings (pending_settings,false);
1059 //m_owner.RemovePendingSettings (m_instance_name);
1060 }
1061}
1062
1063TargetInstanceSettings::~TargetInstanceSettings ()
1064{
1065}
1066
1067TargetInstanceSettings&
1068TargetInstanceSettings::operator= (const TargetInstanceSettings &rhs)
1069{
1070 if (this != &rhs)
1071 {
1072 }
1073
1074 return *this;
1075}
1076
Sean Callanan77e93942010-10-29 00:29:03 +00001077#define EXPR_PREFIX_STRING "expr-prefix"
Caroline Tice5bc8c972010-09-20 20:44:43 +00001078
1079void
1080TargetInstanceSettings::UpdateInstanceSettingsVariable (const ConstString &var_name,
1081 const char *index_value,
1082 const char *value,
1083 const ConstString &instance_name,
1084 const SettingEntry &entry,
1085 lldb::VarSetOperationType op,
1086 Error &err,
1087 bool pending)
1088{
Sean Callanan77e93942010-10-29 00:29:03 +00001089 static ConstString expr_prefix_str (EXPR_PREFIX_STRING);
1090
1091 if (var_name == expr_prefix_str)
1092 {
1093 switch (op)
1094 {
1095 default:
1096 err.SetErrorToGenericError ();
1097 err.SetErrorString ("Unrecognized operation. Cannot update value.\n");
1098 return;
1099 case lldb::eVarSetOperationAssign:
1100 {
1101 FileSpec file_spec(value, true);
1102
1103 if (!file_spec.Exists())
1104 {
1105 err.SetErrorToGenericError ();
1106 err.SetErrorStringWithFormat ("%s does not exist.\n", value);
1107 return;
1108 }
1109
1110 DataBufferMemoryMap buf;
1111
1112 if (!buf.MemoryMapFromFileSpec(&file_spec) &&
1113 buf.GetError().Fail())
1114 {
1115 err.SetErrorToGenericError ();
1116 err.SetErrorStringWithFormat ("Couldn't read from %s: %s\n", value, buf.GetError().AsCString());
1117 return;
1118 }
1119
1120 m_expr_prefix_path = value;
1121 m_expr_prefix_contents.assign(reinterpret_cast<const char *>(buf.GetBytes()), buf.GetByteSize());
1122 }
1123 return;
1124 case lldb::eVarSetOperationAppend:
1125 err.SetErrorToGenericError ();
1126 err.SetErrorString ("Cannot append to a path.\n");
1127 return;
1128 case lldb::eVarSetOperationClear:
1129 m_expr_prefix_path.clear ();
1130 m_expr_prefix_contents.clear ();
1131 return;
1132 }
1133 }
Caroline Tice5bc8c972010-09-20 20:44:43 +00001134}
1135
1136void
1137TargetInstanceSettings::CopyInstanceSettings (const lldb::InstanceSettingsSP &new_settings,
Sean Callanan77e93942010-10-29 00:29:03 +00001138 bool pending)
Caroline Tice5bc8c972010-09-20 20:44:43 +00001139{
Sean Callanan77e93942010-10-29 00:29:03 +00001140 TargetInstanceSettings *new_settings_ptr = static_cast <TargetInstanceSettings *> (new_settings.get());
1141
1142 if (!new_settings_ptr)
1143 return;
1144
1145 m_expr_prefix_path = new_settings_ptr->m_expr_prefix_path;
1146 m_expr_prefix_contents = new_settings_ptr->m_expr_prefix_contents;
Caroline Tice5bc8c972010-09-20 20:44:43 +00001147}
1148
Caroline Ticebcb5b452010-09-20 21:37:42 +00001149bool
Caroline Tice5bc8c972010-09-20 20:44:43 +00001150TargetInstanceSettings::GetInstanceSettingsValue (const SettingEntry &entry,
1151 const ConstString &var_name,
1152 StringList &value,
Caroline Ticebcb5b452010-09-20 21:37:42 +00001153 Error *err)
Caroline Tice5bc8c972010-09-20 20:44:43 +00001154{
Sean Callanan77e93942010-10-29 00:29:03 +00001155 static ConstString expr_prefix_str (EXPR_PREFIX_STRING);
1156
1157 if (var_name == expr_prefix_str)
1158 {
1159 value.AppendString (m_expr_prefix_path.c_str(), m_expr_prefix_path.size());
1160 }
1161 else
1162 {
1163 if (err)
1164 err->SetErrorStringWithFormat ("unrecognized variable name '%s'", var_name.AsCString());
1165 return false;
1166 }
1167
1168 return true;
Caroline Tice5bc8c972010-09-20 20:44:43 +00001169}
1170
1171const ConstString
1172TargetInstanceSettings::CreateInstanceName ()
1173{
Caroline Tice5bc8c972010-09-20 20:44:43 +00001174 StreamString sstr;
Caroline Tice1ebef442010-09-27 00:30:10 +00001175 static int instance_count = 1;
1176
Caroline Tice5bc8c972010-09-20 20:44:43 +00001177 sstr.Printf ("target_%d", instance_count);
1178 ++instance_count;
1179
1180 const ConstString ret_val (sstr.GetData());
1181 return ret_val;
1182}
1183
1184//--------------------------------------------------
1185// Target::SettingsController Variable Tables
1186//--------------------------------------------------
1187
1188SettingEntry
1189Target::SettingsController::global_settings_table[] =
1190{
Sean Callanan77e93942010-10-29 00:29:03 +00001191 //{ "var-name", var-type, "default", enum-table, init'd, hidden, "help-text"},
1192 { "default-arch", eSetVarTypeString, NULL, NULL, false, false, "Default architecture to choose, when there's a choice." },
Caroline Tice5bc8c972010-09-20 20:44:43 +00001193 { NULL, eSetVarTypeNone, NULL, NULL, 0, 0, NULL }
1194};
1195
1196SettingEntry
1197Target::SettingsController::instance_settings_table[] =
1198{
Sean Callanan77e93942010-10-29 00:29:03 +00001199 //{ "var-name", var-type, "default", enum-table, init'd, hidden, "help-text"},
1200 { EXPR_PREFIX_STRING, eSetVarTypeString, NULL, NULL, false, false, "Path to a file containing expressions to be prepended to all expressions." },
Caroline Tice5bc8c972010-09-20 20:44:43 +00001201 { NULL, eSetVarTypeNone, NULL, NULL, 0, 0, NULL }
1202};