void ObjectContainerUniversalMachO::Dump (Stream *s) const { s->Printf("%.*p: ", (int)sizeof(void*) * 2, this); s->Indent(); const size_t num_archs = GetNumArchitectures(); const size_t num_objects = GetNumObjects(); s->Printf("ObjectContainerUniversalMachO, num_archs = %u, num_objects = %u", num_archs, num_objects); uint32_t i; ArchSpec arch; s->IndentMore(); for (i=0; i<num_archs; i++) { s->Indent(); GetArchitectureAtIndex(i, arch); s->Printf("arch[%u] = %s\n", arch.GetArchitectureName()); } for (i=0; i<num_objects; i++) { s->Indent(); s->Printf("object[%u] = %s\n", GetObjectNameAtIndex (i)); } s->IndentLess(); s->EOL(); }
ObjectFile * ObjectContainerUniversalMachO::GetObjectFile (const FileSpec *file) { uint32_t arch_idx = 0; ArchSpec arch; // If the module hasn't specified an architecture yet, set it to the default // architecture: if (!m_module->GetArchitecture().IsValid()) { arch = Target::GetDefaultArchitecture (); if (!arch.IsValid()) arch.SetTriple (LLDB_ARCH_DEFAULT); } else arch = m_module->GetArchitecture(); ArchSpec curr_arch; for (arch_idx = 0; arch_idx < m_header.nfat_arch; ++arch_idx) { if (GetArchitectureAtIndex (arch_idx, curr_arch)) { if (arch == curr_arch) { return ObjectFile::FindPlugin (m_module, file, m_offset + m_fat_archs[arch_idx].offset, m_fat_archs[arch_idx].size); } } } return NULL; }
unsigned POSIXThread::GetRegisterIndexFromOffset(unsigned offset) { unsigned reg = LLDB_INVALID_REGNUM; ArchSpec arch = Host::GetArchitecture(); switch (arch.GetCore()) { default: llvm_unreachable("CPU type not supported!"); break; case ArchSpec::eCore_mips64: case ArchSpec::eCore_x86_32_i386: case ArchSpec::eCore_x86_32_i486: case ArchSpec::eCore_x86_32_i486sx: case ArchSpec::eCore_x86_64_x86_64: { POSIXBreakpointProtocol* reg_ctx = GetPOSIXBreakpointProtocol(); reg = reg_ctx->GetRegisterIndexFromOffset(offset); } break; } return reg; }
lldb::TypeSystemSP GoASTContext::CreateInstance (lldb::LanguageType language, Module *module, Target *target, const char *compiler_options) { if (language == eLanguageTypeGo) { ArchSpec arch; std::shared_ptr<GoASTContext> go_ast_sp; if (module) { arch = module->GetArchitecture(); go_ast_sp = std::shared_ptr<GoASTContext>(new GoASTContext); } else if (target) { arch = target->GetArchitecture(); go_ast_sp = std::shared_ptr<GoASTContextForExpr>(new GoASTContextForExpr(target->shared_from_this())); } if (arch.IsValid()) { go_ast_sp->SetAddressByteSize(arch.GetAddressByteSize()); return go_ast_sp; } } return lldb::TypeSystemSP(); }
lldb::DisassemblerSP Disassembler::DisassembleBytes ( const ArchSpec &arch, const char *plugin_name, const Address &start, const void *bytes, size_t length, uint32_t num_instructions ) { lldb::DisassemblerSP disasm_sp; if (bytes) { disasm_sp.reset(Disassembler::FindPlugin(arch, plugin_name)); if (disasm_sp) { DataExtractor data(bytes, length, arch.GetByteOrder(), arch.GetAddressByteSize()); (void)disasm_sp->DecodeInstructions (start, data, 0, num_instructions, false); } } return disasm_sp; }
unsigned POSIXThread::GetRegisterIndexFromOffset(unsigned offset) { unsigned reg = LLDB_INVALID_REGNUM; ArchSpec arch = Host::GetArchitecture(); switch (arch.GetCore()) { default: llvm_unreachable("CPU type not supported!"); break; case ArchSpec::eCore_x86_32_i386: case ArchSpec::eCore_x86_32_i486: case ArchSpec::eCore_x86_32_i486sx: case ArchSpec::eCore_x86_64_x86_64: { RegisterContextSP base = GetRegisterContext(); if (base) { RegisterContextPOSIX &context = static_cast<RegisterContextPOSIX &>(*base); reg = context.GetRegisterIndexFromOffset(offset); } } break; } return reg; }
lldb::RegisterContextSP POSIXThread::GetRegisterContext() { if (!m_reg_context_sp) { ArchSpec arch = Host::GetArchitecture(); switch (arch.GetCore()) { default: assert(false && "CPU type not supported!"); break; case ArchSpec::eCore_x86_32_i386: case ArchSpec::eCore_x86_32_i486: case ArchSpec::eCore_x86_32_i486sx: m_reg_context_sp.reset(new RegisterContext_i386(*this, 0)); break; case ArchSpec::eCore_x86_64_x86_64: // TODO: Use target OS/architecture detection rather than ifdefs so that // lldb built on FreeBSD can debug on Linux and vice-versa. #ifdef __linux__ m_reg_context_sp.reset(new RegisterContextLinux_x86_64(*this, 0)); #endif #ifdef __FreeBSD__ m_reg_context_sp.reset(new RegisterContextFreeBSD_x86_64(*this, 0)); #endif break; } } return m_reg_context_sp; }
void ObjectFileJIT::Dump (Stream *s) { ModuleSP module_sp(GetModule()); if (module_sp) { lldb_private::Mutex::Locker locker(module_sp->GetMutex()); s->Printf("%p: ", static_cast<void*>(this)); s->Indent(); s->PutCString("ObjectFileJIT"); ArchSpec arch; if (GetArchitecture(arch)) *s << ", arch = " << arch.GetArchitectureName(); s->EOL(); SectionList *sections = GetSectionList(); if (sections) sections->Dump(s, NULL, true, UINT32_MAX); if (m_symtab_ap.get()) m_symtab_ap->Dump(s, NULL, eSortOrderNone); } }
size_t PlatformFreeBSD::GetSoftwareBreakpointTrapOpcode (Target &target, BreakpointSite *bp_site) { ArchSpec arch = target.GetArchitecture(); const uint8_t *trap_opcode = NULL; size_t trap_opcode_size = 0; switch (arch.GetMachine()) { default: llvm_unreachable("Unhandled architecture in PlatformFreeBSD::GetSoftwareBreakpointTrapOpcode()"); break; case llvm::Triple::x86: case llvm::Triple::x86_64: { static const uint8_t g_i386_opcode[] = { 0xCC }; trap_opcode = g_i386_opcode; trap_opcode_size = sizeof(g_i386_opcode); } break; } if (bp_site->SetTrapOpcode(trap_opcode, trap_opcode_size)) return trap_opcode_size; return 0; }
lldb::RegisterContextSP POSIXThread::GetRegisterContext() { if (!m_reg_context_sp) { ArchSpec arch = Host::GetArchitecture(); switch (arch.GetCore()) { default: assert(false && "CPU type not supported!"); break; case ArchSpec::eCore_x86_32_i386: case ArchSpec::eCore_x86_32_i486: case ArchSpec::eCore_x86_32_i486sx: m_reg_context_sp.reset(new RegisterContext_i386(*this, 0)); break; case ArchSpec::eCore_x86_64_x86_64: m_reg_context_sp.reset(new RegisterContext_x86_64(*this, 0)); break; } } return m_reg_context_sp; }
RegisterContextSP TargetThreadWindowsLive::CreateRegisterContextForFrameIndex(uint32_t idx) { if (!m_reg_context_sp) { ArchSpec arch = HostInfo::GetArchitecture(); switch (arch.GetMachine()) { case llvm::Triple::x86: #if defined(_WIN64) // FIXME: This is a Wow64 process, create a RegisterContextWindows_Wow64 #else m_reg_context_sp.reset(new RegisterContextWindowsLive_x86(*this, idx)); #endif break; case llvm::Triple::x86_64: #if defined(_WIN64) m_reg_context_sp.reset(new RegisterContextWindowsLive_x64(*this, idx)); #else // LLDB is 32-bit, but the target process is 64-bit. We probably can't debug // this. #endif default: break; } } return m_reg_context_sp; }
uint64_t Type::GetByteSize() { if (m_byte_size == 0) { switch (m_encoding_uid_type) { case eEncodingInvalid: case eEncodingIsSyntheticUID: break; case eEncodingIsUID: case eEncodingIsConstUID: case eEncodingIsRestrictUID: case eEncodingIsVolatileUID: case eEncodingIsTypedefUID: { Type *encoding_type = GetEncodingType(); if (encoding_type) m_byte_size = encoding_type->GetByteSize(); if (m_byte_size == 0) m_byte_size = GetLayoutCompilerType().GetByteSize(nullptr); } break; // If we are a pointer or reference, then this is just a pointer size; case eEncodingIsPointerUID: case eEncodingIsLValueReferenceUID: case eEncodingIsRValueReferenceUID: { ArchSpec arch; if (m_symbol_file->GetObjectFile()->GetArchitecture(arch)) m_byte_size = arch.GetAddressByteSize(); } break; } } return m_byte_size; }
lldb::DisassemblerSP Disassembler::DisassembleBytes (const ArchSpec &arch, const char *plugin_name, const char *flavor, const Address &start, const void *src, size_t src_len, uint32_t num_instructions, bool data_from_file) { lldb::DisassemblerSP disasm_sp; if (src) { disasm_sp = Disassembler::FindPlugin(arch, flavor, plugin_name); if (disasm_sp) { DataExtractor data(src, src_len, arch.GetByteOrder(), arch.GetAddressByteSize()); (void)disasm_sp->DecodeInstructions (start, data, 0, num_instructions, false, data_from_file); } } return disasm_sp; }
// Parse a FreeBSD NT_PRSTATUS note - see FreeBSD sys/procfs.h for details. static void ParseFreeBSDPrStatus(ThreadData &thread_data, DataExtractor &data, ArchSpec &arch) { lldb::offset_t offset = 0; bool lp64 = (arch.GetMachine() == llvm::Triple::aarch64 || arch.GetMachine() == llvm::Triple::mips64 || arch.GetMachine() == llvm::Triple::ppc64 || arch.GetMachine() == llvm::Triple::x86_64); int pr_version = data.GetU32(&offset); Log *log (GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); if (log) { if (pr_version > 1) log->Printf("FreeBSD PRSTATUS unexpected version %d", pr_version); } // Skip padding, pr_statussz, pr_gregsetsz, pr_fpregsetsz, pr_osreldate if (lp64) offset += 32; else offset += 16; thread_data.signo = data.GetU32(&offset); // pr_cursig thread_data.tid = data.GetU32(&offset); // pr_pid if (lp64) offset += 4; size_t len = data.GetByteSize() - offset; thread_data.gpregset = DataExtractor(data, offset, len); }
DisassemblerLLVMC::DisassemblerLLVMC (const ArchSpec &arch) : Disassembler(arch), m_exe_ctx (NULL), m_inst (NULL), m_disasm_context (NULL), m_alternate_disasm_context (NULL) { m_disasm_context = ::LLVMCreateDisasm(arch.GetTriple().getTriple().c_str(), (void*)this, /*TagType=*/1, NULL, DisassemblerLLVMC::SymbolLookupCallback); if (arch.GetTriple().getArch() == llvm::Triple::arm) { ArchSpec thumb_arch(arch); thumb_arch.GetTriple().setArchName(llvm::StringRef("thumbv7")); std::string thumb_triple(thumb_arch.GetTriple().getTriple()); m_alternate_disasm_context = ::LLVMCreateDisasm(thumb_triple.c_str(), (void*)this, /*TagType=*/1, NULL, DisassemblerLLVMC::SymbolLookupCallback); } }
//---------------------------------------------------------------------- // Disassembler copy constructor //---------------------------------------------------------------------- Disassembler::Disassembler(const ArchSpec& arch, const char *flavor) : m_arch (arch), m_instruction_list(), m_base_addr(LLDB_INVALID_ADDRESS), m_flavor () { if (flavor == NULL) m_flavor.assign("default"); else m_flavor.assign(flavor); // If this is an arm variant that can only include thumb (T16, T32) // instructions, force the arch triple to be "thumbv.." instead of // "armv..." if (arch.GetTriple().getArch() == llvm::Triple::arm && (arch.GetCore() == ArchSpec::Core::eCore_arm_armv7m || arch.GetCore() == ArchSpec::Core::eCore_arm_armv7em || arch.GetCore() == ArchSpec::Core::eCore_arm_armv6m)) { std::string thumb_arch_name (arch.GetTriple().getArchName().str()); // Replace "arm" with "thumb" so we get all thumb variants correct if (thumb_arch_name.size() > 3) { thumb_arch_name.erase(0, 3); thumb_arch_name.insert(0, "thumb"); } m_arch.SetTriple (thumb_arch_name.c_str()); } }
bool PlatformRemoteGDBServer::GetModuleSpec (const FileSpec& module_file_spec, const ArchSpec& arch, ModuleSpec &module_spec) { Log *log = GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PLATFORM); const auto module_path = module_file_spec.GetPath (false); if (!m_gdb_client.GetModuleInfo (module_file_spec, arch, module_spec)) { if (log) log->Printf ("PlatformRemoteGDBServer::%s - failed to get module info for %s:%s", __FUNCTION__, module_path.c_str (), arch.GetTriple ().getTriple ().c_str ()); return false; } if (log) { StreamString stream; module_spec.Dump (stream); log->Printf ("PlatformRemoteGDBServer::%s - got module info for (%s:%s) : %s", __FUNCTION__, module_path.c_str (), arch.GetTriple ().getTriple ().c_str (), stream.GetString ().c_str ()); } return true; }
size_t ProcessPOSIX::GetSoftwareBreakpointTrapOpcode(BreakpointSite* bp_site) { static const uint8_t g_aarch64_opcode[] = { 0x00, 0x00, 0x20, 0xD4 }; static const uint8_t g_i386_opcode[] = { 0xCC }; ArchSpec arch = GetTarget().GetArchitecture(); const uint8_t *opcode = NULL; size_t opcode_size = 0; switch (arch.GetMachine()) { default: assert(false && "CPU type not supported!"); break; case llvm::Triple::aarch64: opcode = g_aarch64_opcode; opcode_size = sizeof(g_aarch64_opcode); break; case llvm::Triple::x86: case llvm::Triple::x86_64: opcode = g_i386_opcode; opcode_size = sizeof(g_i386_opcode); break; } bp_site->SetTrapOpcode(opcode, opcode_size); return opcode_size; }
static bool COFFMachineToMachCPU (uint16_t machine, ArchSpec &arch) { switch (machine) { case IMAGE_FILE_MACHINE_AMD64: case IMAGE_FILE_MACHINE_IA64: arch.SetArchitecture (eArchTypeMachO, llvm::MachO::CPUTypeX86_64, llvm::MachO::CPUSubType_X86_64_ALL); return true; case IMAGE_FILE_MACHINE_I386: arch.SetArchitecture (eArchTypeMachO, llvm::MachO::CPUTypeI386, llvm::MachO::CPUSubType_I386_ALL); return true; case IMAGE_FILE_MACHINE_POWERPC: case IMAGE_FILE_MACHINE_POWERPCFP: arch.SetArchitecture (eArchTypeMachO, llvm::MachO::CPUTypePowerPC, llvm::MachO::CPUSubType_POWERPC_ALL); return true; case IMAGE_FILE_MACHINE_ARM: case IMAGE_FILE_MACHINE_THUMB: arch.SetArchitecture (eArchTypeMachO, llvm::MachO::CPUTypeARM, llvm::MachO::CPUSubType_ARM_V7); return true; } return false; }
unsigned POSIXThread::GetRegisterIndexFromOffset(unsigned offset) { unsigned reg = LLDB_INVALID_REGNUM; ArchSpec arch = HostInfo::GetArchitecture(); switch (arch.GetMachine()) { default: llvm_unreachable("CPU type not supported!"); break; case llvm::Triple::aarch64: case llvm::Triple::arm: case llvm::Triple::mips64: case llvm::Triple::ppc: case llvm::Triple::ppc64: case llvm::Triple::x86: case llvm::Triple::x86_64: { POSIXBreakpointProtocol* reg_ctx = GetPOSIXBreakpointProtocol(); reg = reg_ctx->GetRegisterIndexFromOffset(offset); } break; } return reg; }
bool lldb_private::operator<(const ArchSpec& lhs, const ArchSpec& rhs) { const ArchSpec::Core lhs_core = lhs.GetCore (); const ArchSpec::Core rhs_core = rhs.GetCore (); return lhs_core < rhs_core; }
size_t PlatformFreeBSD::GetSoftwareBreakpointTrapOpcode (Target &target, BreakpointSite *bp_site) { ArchSpec arch = target.GetArchitecture(); const uint8_t *trap_opcode = NULL; size_t trap_opcode_size = 0; switch (arch.GetCore()) { default: assert(false && "Unhandled architecture in PlatformFreeBSD::GetSoftwareBreakpointTrapOpcode()"); break; case ArchSpec::eCore_x86_32_i386: case ArchSpec::eCore_x86_64_x86_64: { static const uint8_t g_i386_opcode[] = { 0xCC }; trap_opcode = g_i386_opcode; trap_opcode_size = sizeof(g_i386_opcode); } break; } if (bp_site->SetTrapOpcode(trap_opcode, trap_opcode_size)) return trap_opcode_size; return 0; }
size_t PlatformLinux::GetSoftwareBreakpointTrapOpcode (Target &target, BreakpointSite *bp_site) { ArchSpec arch = target.GetArchitecture(); const uint8_t *trap_opcode = NULL; size_t trap_opcode_size = 0; switch (arch.GetMachine()) { default: assert(false && "CPU type not supported!"); break; case llvm::Triple::x86: case llvm::Triple::x86_64: { static const uint8_t g_i386_breakpoint_opcode[] = { 0xCC }; trap_opcode = g_i386_breakpoint_opcode; trap_opcode_size = sizeof(g_i386_breakpoint_opcode); } break; case llvm::Triple::hexagon: return 0; } if (bp_site->SetTrapOpcode(trap_opcode, trap_opcode_size)) return trap_opcode_size; return 0; }
void BreakpointLocationList::RemoveInvalidLocations(const ArchSpec &arch) { std::lock_guard<std::recursive_mutex> guard(m_mutex); size_t idx = 0; // Don't cache m_location.size() as it will change since we might remove // locations from our vector... while (idx < m_locations.size()) { BreakpointLocation *bp_loc = m_locations[idx].get(); if (bp_loc->GetAddress().SectionWasDeleted()) { // Section was deleted which means this breakpoint comes from a module // that is no longer valid, so we should remove it. RemoveLocationByIndex(idx); continue; } if (arch.IsValid()) { ModuleSP module_sp(bp_loc->GetAddress().GetModule()); if (module_sp) { if (!arch.IsCompatibleMatch(module_sp->GetArchitecture())) { // The breakpoint was in a module whose architecture is no longer // compatible with "arch", so we need to remove it RemoveLocationByIndex(idx); continue; } } } // Only increment the index if we didn't remove the locations at index // "idx" ++idx; } }
bool OptionGroupArchitecture::GetArchitecture(Platform *platform, ArchSpec &arch) { if (m_arch_str.empty()) arch.Clear(); else arch.SetTriple(m_arch_str.c_str(), platform); return arch.IsValid(); }
bool EmulateInstructionMIPS::SetTargetTriple (const ArchSpec &arch) { if (arch.GetTriple().getArch () == llvm::Triple::mips || arch.GetTriple().getArch () == llvm::Triple::mipsel) return true; return false; }
bool EmulateInstructionARM64::SetTargetTriple(const ArchSpec &arch) { if (arch.GetTriple().getArch() == llvm::Triple::arm) return true; else if (arch.GetTriple().getArch() == llvm::Triple::thumb) return true; return false; }
size_t ProcessFreeBSD::GetSoftwareBreakpointTrapOpcode(BreakpointSite* bp_site) { static const uint8_t g_aarch64_opcode[] = { 0x00, 0x00, 0x20, 0xD4 }; static const uint8_t g_i386_opcode[] = { 0xCC }; ArchSpec arch = GetTarget().GetArchitecture(); const uint8_t *opcode = NULL; size_t opcode_size = 0; switch (arch.GetMachine()) { default: assert(false && "CPU type not supported!"); break; case llvm::Triple::arm: { // The ARM reference recommends the use of 0xe7fddefe and 0xdefe // but the linux kernel does otherwise. static const uint8_t g_arm_breakpoint_opcode[] = { 0xf0, 0x01, 0xf0, 0xe7 }; static const uint8_t g_thumb_breakpoint_opcode[] = { 0x01, 0xde }; lldb::BreakpointLocationSP bp_loc_sp (bp_site->GetOwnerAtIndex (0)); AddressClass addr_class = eAddressClassUnknown; if (bp_loc_sp) addr_class = bp_loc_sp->GetAddress ().GetAddressClass (); if (addr_class == eAddressClassCodeAlternateISA || (addr_class == eAddressClassUnknown && bp_loc_sp->GetAddress().GetOffset() & 1)) { opcode = g_thumb_breakpoint_opcode; opcode_size = sizeof(g_thumb_breakpoint_opcode); } else { opcode = g_arm_breakpoint_opcode; opcode_size = sizeof(g_arm_breakpoint_opcode); } } break; case llvm::Triple::aarch64: opcode = g_aarch64_opcode; opcode_size = sizeof(g_aarch64_opcode); break; case llvm::Triple::x86: case llvm::Triple::x86_64: opcode = g_i386_opcode; opcode_size = sizeof(g_i386_opcode); break; } bp_site->SetTrapOpcode(opcode, opcode_size); return opcode_size; }
RegisterContextSP ThreadMinidump::CreateRegisterContextForFrame(StackFrame *frame) { RegisterContextSP reg_ctx_sp; uint32_t concrete_frame_idx = 0; Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); if (frame) concrete_frame_idx = frame->GetConcreteFrameIndex(); if (concrete_frame_idx == 0) { if (m_thread_reg_ctx_sp) return m_thread_reg_ctx_sp; ProcessMinidump *process = static_cast<ProcessMinidump *>(GetProcess().get()); ArchSpec arch = process->GetArchitecture(); RegisterInfoInterface *reg_interface = nullptr; // TODO write other register contexts and add them here switch (arch.GetMachine()) { case llvm::Triple::x86: { reg_interface = new RegisterContextLinux_i386(arch); lldb::DataBufferSP buf = ConvertMinidumpContext_x86_32(m_gpregset_data, reg_interface); DataExtractor gpregs(buf, lldb::eByteOrderLittle, 4); DataExtractor fpregs; m_thread_reg_ctx_sp.reset(new RegisterContextCorePOSIX_x86_64( *this, reg_interface, gpregs, fpregs)); break; } case llvm::Triple::x86_64: { reg_interface = new RegisterContextLinux_x86_64(arch); lldb::DataBufferSP buf = ConvertMinidumpContext_x86_64(m_gpregset_data, reg_interface); DataExtractor gpregs(buf, lldb::eByteOrderLittle, 8); DataExtractor fpregs; m_thread_reg_ctx_sp.reset(new RegisterContextCorePOSIX_x86_64( *this, reg_interface, gpregs, fpregs)); break; } default: break; } if (!reg_interface) { if (log) log->Printf("elf-core::%s:: Architecture(%d) not supported", __FUNCTION__, arch.GetMachine()); assert(false && "Architecture not supported"); } reg_ctx_sp = m_thread_reg_ctx_sp; } else if (m_unwinder_ap) { reg_ctx_sp = m_unwinder_ap->CreateRegisterContextForFrame(frame); } return reg_ctx_sp; }
void Platform::GetStatus (Stream &strm) { uint32_t major = UINT32_MAX; uint32_t minor = UINT32_MAX; uint32_t update = UINT32_MAX; std::string s; strm.Printf (" Platform: %s\n", GetPluginName().GetCString()); ArchSpec arch (GetSystemArchitecture()); if (arch.IsValid()) { if (!arch.GetTriple().str().empty()) strm.Printf(" Triple: %s\n", arch.GetTriple().str().c_str()); } if (GetOSVersion(major, minor, update)) { strm.Printf("OS Version: %u", major); if (minor != UINT32_MAX) strm.Printf(".%u", minor); if (update != UINT32_MAX) strm.Printf(".%u", update); if (GetOSBuildString (s)) strm.Printf(" (%s)", s.c_str()); strm.EOL(); } if (GetOSKernelDescription (s)) strm.Printf(" Kernel: %s\n", s.c_str()); if (IsHost()) { strm.Printf(" Hostname: %s\n", GetHostname()); } else { const bool is_connected = IsConnected(); if (is_connected) strm.Printf(" Hostname: %s\n", GetHostname()); strm.Printf(" Connected: %s\n", is_connected ? "yes" : "no"); } if (GetWorkingDirectory()) { strm.Printf("WorkingDir: %s\n", GetWorkingDirectory().GetCString()); } if (!IsConnected()) return; std::string specific_info(GetPlatformSpecificConnectionInformation()); if (specific_info.empty() == false) strm.Printf("Platform-specific connection: %s\n", specific_info.c_str()); }