1 //===-- SBTarget.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/API/SBTarget.h"
11 
12 #include "lldb/lldb-include.h"
13 
14 #include "lldb/API/SBFileSpec.h"
15 #include "lldb/API/SBModule.h"
16 #include "lldb/API/SBStream.h"
17 #include "lldb/Breakpoint/BreakpointID.h"
18 #include "lldb/Breakpoint/BreakpointIDList.h"
19 #include "lldb/Breakpoint/BreakpointList.h"
20 #include "lldb/Breakpoint/BreakpointLocation.h"
21 #include "lldb/Core/Address.h"
22 #include "lldb/Core/AddressResolver.h"
23 #include "lldb/Core/AddressResolverName.h"
24 #include "lldb/Interpreter/Args.h"
25 #include "lldb/Core/ArchSpec.h"
26 #include "lldb/Core/Debugger.h"
27 #include "lldb/Core/Disassembler.h"
28 #include "lldb/Core/FileSpec.h"
29 #include "lldb/Core/Log.h"
30 #include "lldb/Core/RegularExpression.h"
31 #include "lldb/Core/SearchFilter.h"
32 #include "lldb/Core/STLUtils.h"
33 #include "lldb/Target/Process.h"
34 #include "lldb/Target/Target.h"
35 #include "lldb/Target/TargetList.h"
36 
37 #include "lldb/Interpreter/CommandReturnObject.h"
38 #include "../source/Commands/CommandObjectBreakpoint.h"
39 
40 #include "lldb/API/SBDebugger.h"
41 #include "lldb/API/SBProcess.h"
42 #include "lldb/API/SBListener.h"
43 #include "lldb/API/SBBreakpoint.h"
44 
45 using namespace lldb;
46 using namespace lldb_private;
47 
48 #define DEFAULT_DISASM_BYTE_SIZE 32
49 
50 //----------------------------------------------------------------------
51 // SBTarget constructor
52 //----------------------------------------------------------------------
53 SBTarget::SBTarget () :
54     m_opaque_sp ()
55 {
56 }
57 
58 SBTarget::SBTarget (const SBTarget& rhs) :
59     m_opaque_sp (rhs.m_opaque_sp)
60 {
61 }
62 
63 SBTarget::SBTarget(const TargetSP& target_sp) :
64     m_opaque_sp (target_sp)
65 {
66 }
67 
68 const SBTarget&
69 SBTarget::operator = (const SBTarget& rhs)
70 {
71     if (this != &rhs)
72         m_opaque_sp = rhs.m_opaque_sp;
73     return *this;
74 }
75 
76 //----------------------------------------------------------------------
77 // Destructor
78 //----------------------------------------------------------------------
79 SBTarget::~SBTarget()
80 {
81 }
82 
83 bool
84 SBTarget::IsValid () const
85 {
86     return m_opaque_sp.get() != NULL;
87 }
88 
89 SBProcess
90 SBTarget::GetProcess ()
91 {
92 
93     SBProcess sb_process;
94     if (m_opaque_sp)
95     {
96         Mutex::Locker api_locker (m_opaque_sp->GetAPIMutex());
97         sb_process.SetProcess (m_opaque_sp->GetProcessSP());
98     }
99 
100     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
101     if (log)
102     {
103         log->Printf ("SBTarget(%p)::GetProcess () => SBProcess(%p)",
104                      m_opaque_sp.get(), sb_process.get());
105     }
106 
107     return sb_process;
108 }
109 
110 SBDebugger
111 SBTarget::GetDebugger () const
112 {
113     SBDebugger debugger;
114     if (m_opaque_sp)
115         debugger.reset (m_opaque_sp->GetDebugger().GetSP());
116     return debugger;
117 }
118 
119 
120 SBProcess
121 SBTarget::Launch
122 (
123     char const **argv,
124     char const **envp,
125     const char *stdin_path,
126     const char *stdout_path,
127     const char *stderr_path,
128     const char *working_directory,
129     uint32_t launch_flags,   // See LaunchFlags
130     bool stop_at_entry,
131     lldb::SBError& error
132 )
133 {
134     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
135 
136     if (log)
137     {
138         log->Printf ("SBTarget(%p)::Launch (argv=%p, envp=%p, stdin=%s, stdout=%s, stderr=%s, working-dir=%s, launch_flags=0x%x, stop_at_entry=%i, &error (%p))...",
139                      m_opaque_sp.get(),
140                      argv,
141                      envp,
142                      stdin_path ? stdin_path : "NULL",
143                      stdout_path ? stdout_path : "NULL",
144                      stderr_path ? stderr_path : "NULL",
145                      working_directory ? working_directory : "NULL",
146                      launch_flags,
147                      stop_at_entry,
148                      error.get());
149     }
150     SBProcess sb_process;
151     if (m_opaque_sp)
152     {
153         Mutex::Locker api_locker (m_opaque_sp->GetAPIMutex());
154 
155         if (getenv("LLDB_LAUNCH_FLAG_DISABLE_ASLR"))
156             launch_flags |= eLaunchFlagDisableASLR;
157 
158         static const char *g_launch_tty = NULL;
159         static bool g_got_launch_tty = false;
160         if (!g_got_launch_tty)
161         {
162             // Get the LLDB_LAUNCH_FLAG_LAUNCH_IN_TTY only once
163             g_got_launch_tty = true;
164             g_launch_tty = ::getenv ("LLDB_LAUNCH_FLAG_LAUNCH_IN_TTY");
165             if (g_launch_tty)
166             {
167                 // LLDB_LAUNCH_FLAG_LAUNCH_IN_TTY is a path to a terminal to reuse
168                 // if the first character is '/', else it is a boolean value.
169                 if (g_launch_tty[0] != '/')
170                 {
171                     if (Args::StringToBoolean(g_launch_tty, false, NULL))
172                         g_launch_tty = "";
173                     else
174                         g_launch_tty = NULL;
175                 }
176             }
177         }
178 
179         if ((launch_flags & eLaunchFlagLaunchInTTY) || g_launch_tty)
180         {
181             ArchSpec arch (m_opaque_sp->GetArchitecture ());
182 
183             Module *exe_module = m_opaque_sp->GetExecutableModule().get();
184             if (exe_module)
185             {
186                 char exec_file_path[PATH_MAX];
187                 exe_module->GetFileSpec().GetPath(exec_file_path, sizeof(exec_file_path));
188                 if (exe_module->GetFileSpec().Exists())
189                 {
190                     // Make a new argument vector
191                     std::vector<const char *> exec_path_plus_argv;
192                     // Append the resolved executable path
193                     exec_path_plus_argv.push_back (exec_file_path);
194 
195                     // Push all args if there are any
196                     if (argv)
197                     {
198                         for (int i = 0; argv[i]; ++i)
199                             exec_path_plus_argv.push_back(argv[i]);
200                     }
201 
202                     // Push a NULL to terminate the args.
203                     exec_path_plus_argv.push_back(NULL);
204 
205 
206                     const char *tty_name = NULL;
207                     if (g_launch_tty && g_launch_tty[0] == '/')
208                         tty_name = g_launch_tty;
209 
210                     lldb::pid_t pid = Host::LaunchInNewTerminal (tty_name,
211                                                                  &exec_path_plus_argv[0],
212                                                                  envp,
213                                                                  working_directory,
214                                                                  &arch,
215                                                                  true,
216                                                                  launch_flags & eLaunchFlagDisableASLR);
217 
218                     if (pid != LLDB_INVALID_PROCESS_ID)
219                     {
220                         sb_process = AttachToProcessWithID(pid, error);
221                     }
222                     else
223                     {
224                         error.SetErrorStringWithFormat("failed to launch process in terminal");
225                     }
226                 }
227                 else
228                 {
229                     error.SetErrorStringWithFormat("executable doesn't exist: \"%s\"", exec_file_path);
230                 }
231             }
232             else
233             {
234                 error.SetErrorStringWithFormat("invalid executable");
235             }
236         }
237         else
238         {
239             sb_process.SetProcess (m_opaque_sp->CreateProcess (m_opaque_sp->GetDebugger().GetListener()));
240 
241             if (sb_process.IsValid())
242             {
243 
244                 if (getenv("LLDB_LAUNCH_FLAG_DISABLE_STDIO"))
245                     launch_flags |= eLaunchFlagDisableSTDIO;
246 
247 
248                 error.SetError (sb_process->Launch (argv, envp, launch_flags, stdin_path, stdout_path, stderr_path, working_directory));
249                 if (error.Success())
250                 {
251                     // We we are stopping at the entry point, we can return now!
252                     if (stop_at_entry)
253                         return sb_process;
254 
255                     // Make sure we are stopped at the entry
256                     StateType state = sb_process->WaitForProcessToStop (NULL);
257                     if (state == eStateStopped)
258                     {
259                         // resume the process to skip the entry point
260                         error.SetError (sb_process->Resume());
261                         if (error.Success())
262                         {
263                             // If we are doing synchronous mode, then wait for the
264                             // process to stop yet again!
265                             if (m_opaque_sp->GetDebugger().GetAsyncExecution () == false)
266                                 sb_process->WaitForProcessToStop (NULL);
267                         }
268                     }
269                 }
270             }
271             else
272             {
273                 error.SetErrorString ("unable to create lldb_private::Process");
274             }
275         }
276     }
277     else
278     {
279         error.SetErrorString ("SBTarget is invalid");
280     }
281 
282     log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API);
283     if (log)
284     {
285         log->Printf ("SBTarget(%p)::Launch (...) => SBProceess(%p)",
286                      m_opaque_sp.get(), sb_process.get());
287     }
288 
289     return sb_process;
290 }
291 
292 
293 lldb::SBProcess
294 SBTarget::AttachToProcessWithID
295 (
296     lldb::pid_t pid,// The process ID to attach to
297     SBError& error  // An error explaining what went wrong if attach fails
298 )
299 {
300     SBProcess sb_process;
301     if (m_opaque_sp)
302     {
303         Mutex::Locker api_locker (m_opaque_sp->GetAPIMutex());
304         sb_process.SetProcess (m_opaque_sp->CreateProcess (m_opaque_sp->GetDebugger().GetListener()));
305 
306         if (sb_process.IsValid())
307         {
308             error.SetError (sb_process->Attach (pid));
309         }
310         else
311         {
312             error.SetErrorString ("unable to create lldb_private::Process");
313         }
314     }
315     else
316     {
317         error.SetErrorString ("SBTarget is invalid");
318     }
319     return sb_process;
320 
321 }
322 
323 lldb::SBProcess
324 SBTarget::AttachToProcessWithName
325 (
326     const char *name,   // basename of process to attach to
327     bool wait_for,      // if true wait for a new instance of "name" to be launched
328     SBError& error      // An error explaining what went wrong if attach fails
329 )
330 {
331     SBProcess sb_process;
332     if (m_opaque_sp)
333     {
334         Mutex::Locker api_locker (m_opaque_sp->GetAPIMutex());
335 
336         sb_process.SetProcess (m_opaque_sp->CreateProcess (m_opaque_sp->GetDebugger().GetListener()));
337 
338         if (sb_process.IsValid())
339         {
340             error.SetError (sb_process->Attach (name, wait_for));
341         }
342         else
343         {
344             error.SetErrorString ("unable to create lldb_private::Process");
345         }
346     }
347     else
348     {
349         error.SetErrorString ("SBTarget is invalid");
350     }
351     return sb_process;
352 
353 }
354 
355 SBFileSpec
356 SBTarget::GetExecutable ()
357 {
358 
359     SBFileSpec exe_file_spec;
360     if (m_opaque_sp)
361     {
362         ModuleSP exe_module_sp (m_opaque_sp->GetExecutableModule ());
363         if (exe_module_sp)
364             exe_file_spec.SetFileSpec (exe_module_sp->GetFileSpec());
365     }
366 
367     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
368     if (log)
369     {
370         log->Printf ("SBTarget(%p)::GetExecutable () => SBFileSpec(%p)",
371                      m_opaque_sp.get(), exe_file_spec.get());
372     }
373 
374     return exe_file_spec;
375 }
376 
377 
378 bool
379 SBTarget::DeleteTargetFromList (TargetList *list)
380 {
381     if (m_opaque_sp)
382         return list->DeleteTarget (m_opaque_sp);
383     else
384         return false;
385 }
386 
387 bool
388 SBTarget::operator == (const SBTarget &rhs) const
389 {
390     return m_opaque_sp.get() == rhs.m_opaque_sp.get();
391 }
392 
393 bool
394 SBTarget::operator != (const SBTarget &rhs) const
395 {
396     return m_opaque_sp.get() != rhs.m_opaque_sp.get();
397 }
398 
399 lldb_private::Target *
400 SBTarget::operator ->() const
401 {
402     return m_opaque_sp.get();
403 }
404 
405 lldb_private::Target *
406 SBTarget::get() const
407 {
408     return m_opaque_sp.get();
409 }
410 
411 void
412 SBTarget::reset (const lldb::TargetSP& target_sp)
413 {
414     m_opaque_sp = target_sp;
415 }
416 
417 bool
418 SBTarget::ResolveLoadAddress (lldb::addr_t vm_addr,
419                               lldb::SBAddress& addr)
420 {
421     if (m_opaque_sp)
422     {
423         Mutex::Locker api_locker (m_opaque_sp->GetAPIMutex());
424         return m_opaque_sp->GetSectionLoadList().ResolveLoadAddress (vm_addr, *addr);
425     }
426 
427     addr->Clear();
428     return false;
429 }
430 
431 SBBreakpoint
432 SBTarget::BreakpointCreateByLocation (const char *file, uint32_t line)
433 {
434     return SBBreakpoint(BreakpointCreateByLocation (SBFileSpec (file, false), line));
435 }
436 
437 SBBreakpoint
438 SBTarget::BreakpointCreateByLocation (const SBFileSpec &sb_file_spec, uint32_t line)
439 {
440     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
441 
442     SBBreakpoint sb_bp;
443     if (m_opaque_sp.get() && line != 0)
444     {
445         Mutex::Locker api_locker (m_opaque_sp->GetAPIMutex());
446         *sb_bp = m_opaque_sp->CreateBreakpoint (NULL, *sb_file_spec, line, true, false);
447     }
448 
449     if (log)
450     {
451         SBStream sstr;
452         sb_bp.GetDescription (sstr);
453         char path[PATH_MAX];
454         sb_file_spec->GetPath (path, sizeof(path));
455         log->Printf ("SBTarget(%p)::BreakpointCreateByLocation ( %s:%u ) => SBBreakpoint(%p): %s",
456                      m_opaque_sp.get(),
457                      path,
458                      line,
459                      sb_bp.get(),
460                      sstr.GetData());
461     }
462 
463     return sb_bp;
464 }
465 
466 SBBreakpoint
467 SBTarget::BreakpointCreateByName (const char *symbol_name, const char *module_name)
468 {
469     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
470 
471     SBBreakpoint sb_bp;
472     if (m_opaque_sp.get() && symbol_name && symbol_name[0])
473     {
474         Mutex::Locker api_locker (m_opaque_sp->GetAPIMutex());
475         if (module_name && module_name[0])
476         {
477             FileSpec module_file_spec(module_name, false);
478             *sb_bp = m_opaque_sp->CreateBreakpoint (&module_file_spec, symbol_name, eFunctionNameTypeFull | eFunctionNameTypeBase, false);
479         }
480         else
481         {
482             *sb_bp = m_opaque_sp->CreateBreakpoint (NULL, symbol_name, eFunctionNameTypeFull | eFunctionNameTypeBase, false);
483         }
484     }
485 
486     if (log)
487     {
488         log->Printf ("SBTarget(%p)::BreakpointCreateByName (symbol=\"%s\", module=\"%s\") => SBBreakpoint(%p)",
489                      m_opaque_sp.get(), symbol_name, module_name, sb_bp.get());
490     }
491 
492     return sb_bp;
493 }
494 
495 SBBreakpoint
496 SBTarget::BreakpointCreateByRegex (const char *symbol_name_regex, const char *module_name)
497 {
498     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
499 
500     SBBreakpoint sb_bp;
501     if (m_opaque_sp.get() && symbol_name_regex && symbol_name_regex[0])
502     {
503         Mutex::Locker api_locker (m_opaque_sp->GetAPIMutex());
504         RegularExpression regexp(symbol_name_regex);
505 
506         if (module_name && module_name[0])
507         {
508             FileSpec module_file_spec(module_name, false);
509 
510             *sb_bp = m_opaque_sp->CreateBreakpoint (&module_file_spec, regexp, false);
511         }
512         else
513         {
514             *sb_bp = m_opaque_sp->CreateBreakpoint (NULL, regexp, false);
515         }
516     }
517 
518     if (log)
519     {
520         log->Printf ("SBTarget(%p)::BreakpointCreateByRegex (symbol_regex=\"%s\", module_name=\"%s\") => SBBreakpoint(%p)",
521                      m_opaque_sp.get(), symbol_name_regex, module_name, sb_bp.get());
522     }
523 
524     return sb_bp;
525 }
526 
527 
528 
529 SBBreakpoint
530 SBTarget::BreakpointCreateByAddress (addr_t address)
531 {
532     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
533 
534     SBBreakpoint sb_bp;
535     if (m_opaque_sp.get())
536     {
537         Mutex::Locker api_locker (m_opaque_sp->GetAPIMutex());
538         *sb_bp = m_opaque_sp->CreateBreakpoint (address, false);
539     }
540 
541     if (log)
542     {
543         log->Printf ("SBTarget(%p)::BreakpointCreateByAddress (%p, address=%p) => SBBreakpoint(%p)", m_opaque_sp.get(), address, sb_bp.get());
544     }
545 
546     return sb_bp;
547 }
548 
549 SBBreakpoint
550 SBTarget::FindBreakpointByID (break_id_t bp_id)
551 {
552     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
553 
554     SBBreakpoint sb_breakpoint;
555     if (m_opaque_sp && bp_id != LLDB_INVALID_BREAK_ID)
556     {
557         Mutex::Locker api_locker (m_opaque_sp->GetAPIMutex());
558         *sb_breakpoint = m_opaque_sp->GetBreakpointByID (bp_id);
559     }
560 
561     if (log)
562     {
563         log->Printf ("SBTarget(%p)::FindBreakpointByID (bp_id=%d) => SBBreakpoint(%p)",
564                      m_opaque_sp.get(), (uint32_t) bp_id, sb_breakpoint.get());
565     }
566 
567     return sb_breakpoint;
568 }
569 
570 uint32_t
571 SBTarget::GetNumBreakpoints () const
572 {
573     if (m_opaque_sp)
574     {
575         // The breakpoint list is thread safe, no need to lock
576         return m_opaque_sp->GetBreakpointList().GetSize();
577     }
578     return 0;
579 }
580 
581 SBBreakpoint
582 SBTarget::GetBreakpointAtIndex (uint32_t idx) const
583 {
584     SBBreakpoint sb_breakpoint;
585     if (m_opaque_sp)
586     {
587         // The breakpoint list is thread safe, no need to lock
588         *sb_breakpoint = m_opaque_sp->GetBreakpointList().GetBreakpointAtIndex(idx);
589     }
590     return sb_breakpoint;
591 }
592 
593 bool
594 SBTarget::BreakpointDelete (break_id_t bp_id)
595 {
596     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
597 
598     bool result = false;
599     if (m_opaque_sp)
600     {
601         Mutex::Locker api_locker (m_opaque_sp->GetAPIMutex());
602         result = m_opaque_sp->RemoveBreakpointByID (bp_id);
603     }
604 
605     if (log)
606     {
607         log->Printf ("SBTarget(%p)::BreakpointDelete (bp_id=%d) => %i", m_opaque_sp.get(), (uint32_t) bp_id, result);
608     }
609 
610     return result;
611 }
612 
613 bool
614 SBTarget::EnableAllBreakpoints ()
615 {
616     if (m_opaque_sp)
617     {
618         Mutex::Locker api_locker (m_opaque_sp->GetAPIMutex());
619         m_opaque_sp->EnableAllBreakpoints ();
620         return true;
621     }
622     return false;
623 }
624 
625 bool
626 SBTarget::DisableAllBreakpoints ()
627 {
628     if (m_opaque_sp)
629     {
630         Mutex::Locker api_locker (m_opaque_sp->GetAPIMutex());
631         m_opaque_sp->DisableAllBreakpoints ();
632         return true;
633     }
634     return false;
635 }
636 
637 bool
638 SBTarget::DeleteAllBreakpoints ()
639 {
640     if (m_opaque_sp)
641     {
642         Mutex::Locker api_locker (m_opaque_sp->GetAPIMutex());
643         m_opaque_sp->RemoveAllBreakpoints ();
644         return true;
645     }
646     return false;
647 }
648 
649 
650 uint32_t
651 SBTarget::GetNumModules () const
652 {
653     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
654 
655     uint32_t num = 0;
656     if (m_opaque_sp)
657     {
658         // The module list is thread safe, no need to lock
659         num = m_opaque_sp->GetImages().GetSize();
660     }
661 
662     if (log)
663         log->Printf ("SBTarget(%p)::GetNumModules () => %d", m_opaque_sp.get(), num);
664 
665     return num;
666 }
667 
668 void
669 SBTarget::Clear ()
670 {
671     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
672 
673     if (log)
674         log->Printf ("SBTarget(%p)::Clear ()", m_opaque_sp.get());
675 
676     m_opaque_sp.reset();
677 }
678 
679 
680 SBModule
681 SBTarget::FindModule (const SBFileSpec &sb_file_spec)
682 {
683     SBModule sb_module;
684     if (m_opaque_sp && sb_file_spec.IsValid())
685     {
686         // The module list is thread safe, no need to lock
687         sb_module.SetModule (m_opaque_sp->GetImages().FindFirstModuleForFileSpec (*sb_file_spec, NULL));
688     }
689     return sb_module;
690 }
691 
692 SBModule
693 SBTarget::GetModuleAtIndex (uint32_t idx)
694 {
695     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
696 
697     SBModule sb_module;
698     if (m_opaque_sp)
699     {
700         // The module list is thread safe, no need to lock
701         sb_module.SetModule(m_opaque_sp->GetImages().GetModuleAtIndex(idx));
702     }
703 
704     if (log)
705     {
706         log->Printf ("SBTarget(%p)::GetModuleAtIndex (idx=%d) => SBModule(%p)",
707                      m_opaque_sp.get(), idx, sb_module.get());
708     }
709 
710     return sb_module;
711 }
712 
713 
714 SBBroadcaster
715 SBTarget::GetBroadcaster () const
716 {
717     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
718 
719     SBBroadcaster broadcaster(m_opaque_sp.get(), false);
720 
721     if (log)
722         log->Printf ("SBTarget(%p)::GetBroadcaster () => SBBroadcaster(%p)",
723                      m_opaque_sp.get(), broadcaster.get());
724 
725     return broadcaster;
726 }
727 
728 
729 bool
730 SBTarget::GetDescription (SBStream &description, lldb::DescriptionLevel description_level)
731 {
732     if (m_opaque_sp)
733     {
734         description.ref();
735         m_opaque_sp->Dump (description.get(), description_level);
736     }
737     else
738         description.Printf ("No value");
739 
740     return true;
741 }
742 
743 bool
744 SBTarget::GetDescription (SBStream &description, lldb::DescriptionLevel description_level) const
745 {
746     if (m_opaque_sp)
747     {
748         description.ref();
749         m_opaque_sp->Dump (description.get(), description_level);
750     }
751     else
752         description.Printf ("No value");
753 
754     return true;
755 }
756