604 lines · cpp
1//===-- PlatformLinux.cpp -------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "PlatformLinux.h"10#include "lldb/Host/Config.h"11 12#include <cstdio>13#if LLDB_ENABLE_POSIX14#include <sys/utsname.h>15#endif16 17#include "Plugins/Process/Utility/LinuxSignals.h"18#include "Utility/ARM64_DWARF_Registers.h"19#include "lldb/Core/Debugger.h"20#include "lldb/Core/PluginManager.h"21#include "lldb/Host/HostInfo.h"22#include "lldb/Symbol/UnwindPlan.h"23#include "lldb/Target/Process.h"24#include "lldb/Target/Target.h"25#include "lldb/Utility/FileSpec.h"26#include "lldb/Utility/LLDBLog.h"27#include "lldb/Utility/Log.h"28#include "lldb/Utility/State.h"29#include "lldb/Utility/Status.h"30#include "lldb/Utility/StreamString.h"31 32// Define these constants from Linux mman.h for use when targeting remote linux33// systems even when host has different values.34#define MAP_PRIVATE 235#define MAP_ANON 0x2036 37// For other platforms that use platform linux38#ifndef SIGILL39#define SIGILL 440#endif41#ifndef SIGBUS42#define SIGBUS 743#endif44#ifndef SIGFPE45#define SIGFPE 846#endif47#ifndef SIGSEGV48#define SIGSEGV 1149#endif50 51using namespace lldb;52using namespace lldb_private;53using namespace lldb_private::platform_linux;54 55LLDB_PLUGIN_DEFINE(PlatformLinux)56 57static uint32_t g_initialize_count = 0;58 59 60PlatformSP PlatformLinux::CreateInstance(bool force, const ArchSpec *arch) {61 Log *log = GetLog(LLDBLog::Platform);62 LLDB_LOG(log, "force = {0}, arch=({1}, {2})", force,63 arch ? arch->GetArchitectureName() : "<null>",64 arch ? arch->GetTriple().getTriple() : "<null>");65 66 bool create = force;67 if (!create && arch && arch->IsValid()) {68 const llvm::Triple &triple = arch->GetTriple();69 switch (triple.getOS()) {70 case llvm::Triple::Linux:71 create = true;72 break;73 74#if defined(__linux__)75 // Only accept "unknown" for the OS if the host is linux and it "unknown"76 // wasn't specified (it was just returned because it was NOT specified)77 case llvm::Triple::OSType::UnknownOS:78 create = !arch->TripleOSWasSpecified();79 break;80#endif81 default:82 break;83 }84 }85 86 LLDB_LOG(log, "create = {0}", create);87 if (create) {88 return PlatformSP(new PlatformLinux(false));89 }90 return PlatformSP();91}92 93llvm::StringRef PlatformLinux::GetPluginDescriptionStatic(bool is_host) {94 if (is_host)95 return "Local Linux user platform plug-in.";96 return "Remote Linux user platform plug-in.";97}98 99void PlatformLinux::Initialize() {100 PlatformPOSIX::Initialize();101 102 if (g_initialize_count++ == 0) {103#if defined(__linux__) && !defined(__ANDROID__)104 PlatformSP default_platform_sp(new PlatformLinux(true));105 default_platform_sp->SetSystemArchitecture(HostInfo::GetArchitecture());106 Platform::SetHostPlatform(default_platform_sp);107#endif108 PluginManager::RegisterPlugin(109 PlatformLinux::GetPluginNameStatic(false),110 PlatformLinux::GetPluginDescriptionStatic(false),111 PlatformLinux::CreateInstance, nullptr);112 }113}114 115void PlatformLinux::Terminate() {116 if (g_initialize_count > 0) {117 if (--g_initialize_count == 0) {118 PluginManager::UnregisterPlugin(PlatformLinux::CreateInstance);119 }120 }121 122 PlatformPOSIX::Terminate();123}124 125/// Default Constructor126PlatformLinux::PlatformLinux(bool is_host)127 : PlatformPOSIX(is_host) // This is the local host platform128{129 if (is_host) {130 ArchSpec hostArch = HostInfo::GetArchitecture(HostInfo::eArchKindDefault);131 m_supported_architectures.push_back(hostArch);132 if (hostArch.GetTriple().isArch64Bit()) {133 m_supported_architectures.push_back(134 HostInfo::GetArchitecture(HostInfo::eArchKind32));135 }136 } else {137 m_supported_architectures = CreateArchList(138 {llvm::Triple::x86_64, llvm::Triple::x86, llvm::Triple::arm,139 llvm::Triple::aarch64, llvm::Triple::mips64, llvm::Triple::mips64,140 llvm::Triple::hexagon, llvm::Triple::mips, llvm::Triple::mips64el,141 llvm::Triple::mipsel, llvm::Triple::msp430, llvm::Triple::systemz,142 llvm::Triple::loongarch64, llvm::Triple::ppc64le,143 llvm::Triple::riscv64},144 llvm::Triple::Linux);145 }146}147 148std::vector<ArchSpec>149PlatformLinux::GetSupportedArchitectures(const ArchSpec &process_host_arch) {150 if (m_remote_platform_sp)151 return m_remote_platform_sp->GetSupportedArchitectures(process_host_arch);152 return m_supported_architectures;153}154 155void PlatformLinux::GetStatus(Stream &strm) {156 Platform::GetStatus(strm);157 158#if LLDB_ENABLE_POSIX159 // Display local kernel information only when we are running in host mode.160 // Otherwise, we would end up printing non-Linux information (when running on161 // Mac OS for example).162 if (IsHost()) {163 struct utsname un;164 165 if (uname(&un))166 return;167 168 strm.Printf(" Kernel: %s\n", un.sysname);169 strm.Printf(" Release: %s\n", un.release);170 strm.Printf(" Version: %s\n", un.version);171 }172#endif173}174 175uint32_t176PlatformLinux::GetResumeCountForLaunchInfo(ProcessLaunchInfo &launch_info) {177 uint32_t resume_count = 0;178 179 // Always resume past the initial stop when we use eLaunchFlagDebug180 if (launch_info.GetFlags().Test(eLaunchFlagDebug)) {181 // Resume past the stop for the final exec into the true inferior.182 ++resume_count;183 }184 185 // If we're not launching a shell, we're done.186 const FileSpec &shell = launch_info.GetShell();187 if (!shell)188 return resume_count;189 190 std::string shell_string = shell.GetPath();191 // We're in a shell, so for sure we have to resume past the shell exec.192 ++resume_count;193 194 // Figure out what shell we're planning on using.195 const char *shell_name = strrchr(shell_string.c_str(), '/');196 if (shell_name == nullptr)197 shell_name = shell_string.c_str();198 else199 shell_name++;200 201 if (strcmp(shell_name, "csh") == 0 || strcmp(shell_name, "tcsh") == 0 ||202 strcmp(shell_name, "zsh") == 0 || strcmp(shell_name, "sh") == 0) {203 // These shells seem to re-exec themselves. Add another resume.204 ++resume_count;205 }206 207 return resume_count;208}209 210bool PlatformLinux::CanDebugProcess() {211 if (IsHost()) {212 return true;213 } else {214 // If we're connected, we can debug.215 return IsConnected();216 }217}218 219void PlatformLinux::CalculateTrapHandlerSymbolNames() {220 m_trap_handlers.push_back(ConstString("_sigtramp"));221 m_trap_handlers.push_back(ConstString("__kernel_rt_sigreturn"));222 m_trap_handlers.push_back(ConstString("__restore_rt"));223}224 225static lldb::UnwindPlanSP GetAArch64TrapHandlerUnwindPlan(ConstString name) {226 UnwindPlanSP unwind_plan_sp;227 if (name != "__kernel_rt_sigreturn")228 return unwind_plan_sp;229 230 UnwindPlan::Row row;231 232 // In the signal trampoline frame, sp points to an rt_sigframe[1], which is:233 // - 128-byte siginfo struct234 // - ucontext struct:235 // - 8-byte long (uc_flags)236 // - 8-byte pointer (uc_link)237 // - 24-byte stack_t238 // - 128-byte signal set239 // - 8 bytes of padding because sigcontext has 16-byte alignment240 // - sigcontext/mcontext_t241 // [1]242 // https://github.com/torvalds/linux/blob/master/arch/arm64/kernel/signal.c243 int32_t offset = 128 + 8 + 8 + 24 + 128 + 8;244 // Then sigcontext[2] is:245 // - 8 byte fault address246 // - 31 8 byte registers247 // - 8 byte sp248 // - 8 byte pc249 // [2]250 // https://github.com/torvalds/linux/blob/master/arch/arm64/include/uapi/asm/sigcontext.h251 252 // Skip fault address253 offset += 8;254 row.GetCFAValue().SetIsRegisterPlusOffset(arm64_dwarf::sp, offset);255 256 row.SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x0, 0 * 8, false);257 row.SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x1, 1 * 8, false);258 row.SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x2, 2 * 8, false);259 row.SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x3, 3 * 8, false);260 row.SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x4, 4 * 8, false);261 row.SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x5, 5 * 8, false);262 row.SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x6, 6 * 8, false);263 row.SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x7, 7 * 8, false);264 row.SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x8, 8 * 8, false);265 row.SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x9, 9 * 8, false);266 row.SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x10, 10 * 8, false);267 row.SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x11, 11 * 8, false);268 row.SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x12, 12 * 8, false);269 row.SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x13, 13 * 8, false);270 row.SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x14, 14 * 8, false);271 row.SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x15, 15 * 8, false);272 row.SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x16, 16 * 8, false);273 row.SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x17, 17 * 8, false);274 row.SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x18, 18 * 8, false);275 row.SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x19, 19 * 8, false);276 row.SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x20, 20 * 8, false);277 row.SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x21, 21 * 8, false);278 row.SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x22, 22 * 8, false);279 row.SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x23, 23 * 8, false);280 row.SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x24, 24 * 8, false);281 row.SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x25, 25 * 8, false);282 row.SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x26, 26 * 8, false);283 row.SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x27, 27 * 8, false);284 row.SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x28, 28 * 8, false);285 row.SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::fp, 29 * 8, false);286 row.SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x30, 30 * 8, false);287 row.SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::sp, 31 * 8, false);288 row.SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::pc, 32 * 8, false);289 290 // The sigcontext may also contain floating point and SVE registers.291 // However this would require a dynamic unwind plan so they are not included292 // here.293 294 unwind_plan_sp = std::make_shared<UnwindPlan>(eRegisterKindDWARF);295 unwind_plan_sp->AppendRow(std::move(row));296 unwind_plan_sp->SetSourceName("AArch64 Linux sigcontext");297 unwind_plan_sp->SetSourcedFromCompiler(eLazyBoolYes);298 // Because sp is the same throughout the function299 unwind_plan_sp->SetUnwindPlanValidAtAllInstructions(eLazyBoolYes);300 unwind_plan_sp->SetUnwindPlanForSignalTrap(eLazyBoolYes);301 302 return unwind_plan_sp;303}304 305lldb::UnwindPlanSP306PlatformLinux::GetTrapHandlerUnwindPlan(const llvm::Triple &triple,307 ConstString name) {308 if (triple.isAArch64())309 return GetAArch64TrapHandlerUnwindPlan(name);310 311 return {};312}313 314MmapArgList PlatformLinux::GetMmapArgumentList(const ArchSpec &arch,315 addr_t addr, addr_t length,316 unsigned prot, unsigned flags,317 addr_t fd, addr_t offset) {318 uint64_t flags_platform = 0;319 uint64_t map_anon = arch.IsMIPS() ? 0x800 : MAP_ANON;320 321 if (flags & eMmapFlagsPrivate)322 flags_platform |= MAP_PRIVATE;323 if (flags & eMmapFlagsAnon)324 flags_platform |= map_anon;325 326 MmapArgList args({addr, length, prot, flags_platform, fd, offset});327 return args;328}329 330CompilerType PlatformLinux::GetSiginfoType(const llvm::Triple &triple) {331 {332 std::lock_guard<std::mutex> guard(m_mutex);333 if (!m_type_system)334 m_type_system = std::make_shared<TypeSystemClang>("siginfo", triple);335 }336 TypeSystemClang *ast = m_type_system.get();337 338 bool si_errno_then_code = true;339 340 switch (triple.getArch()) {341 case llvm::Triple::mips:342 case llvm::Triple::mipsel:343 case llvm::Triple::mips64:344 case llvm::Triple::mips64el:345 // mips has si_code and si_errno swapped346 si_errno_then_code = false;347 break;348 default:349 break;350 }351 352 // generic types353 CompilerType int_type = ast->GetBasicType(eBasicTypeInt);354 CompilerType uint_type = ast->GetBasicType(eBasicTypeUnsignedInt);355 CompilerType short_type = ast->GetBasicType(eBasicTypeShort);356 CompilerType long_type = ast->GetBasicType(eBasicTypeLong);357 CompilerType voidp_type = ast->GetBasicType(eBasicTypeVoid).GetPointerType();358 359 // platform-specific types360 CompilerType &pid_type = int_type;361 CompilerType &uid_type = uint_type;362 CompilerType &clock_type = long_type;363 CompilerType &band_type = long_type;364 365 CompilerType sigval_type = ast->CreateRecordType(366 nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "__lldb_sigval_t",367 llvm::to_underlying(clang::TagTypeKind::Union), lldb::eLanguageTypeC);368 ast->StartTagDeclarationDefinition(sigval_type);369 ast->AddFieldToRecordType(sigval_type, "sival_int", int_type,370 lldb::eAccessPublic, 0);371 ast->AddFieldToRecordType(sigval_type, "sival_ptr", voidp_type,372 lldb::eAccessPublic, 0);373 ast->CompleteTagDeclarationDefinition(sigval_type);374 375 CompilerType sigfault_bounds_type = ast->CreateRecordType(376 nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "",377 llvm::to_underlying(clang::TagTypeKind::Union), lldb::eLanguageTypeC);378 ast->StartTagDeclarationDefinition(sigfault_bounds_type);379 ast->AddFieldToRecordType(380 sigfault_bounds_type, "_addr_bnd",381 ast->CreateStructForIdentifier(llvm::StringRef(),382 {383 {"_lower", voidp_type},384 {"_upper", voidp_type},385 }),386 lldb::eAccessPublic, 0);387 ast->AddFieldToRecordType(sigfault_bounds_type, "_pkey", uint_type,388 lldb::eAccessPublic, 0);389 ast->CompleteTagDeclarationDefinition(sigfault_bounds_type);390 391 // siginfo_t392 CompilerType siginfo_type = ast->CreateRecordType(393 nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "__lldb_siginfo_t",394 llvm::to_underlying(clang::TagTypeKind::Struct), lldb::eLanguageTypeC);395 ast->StartTagDeclarationDefinition(siginfo_type);396 ast->AddFieldToRecordType(siginfo_type, "si_signo", int_type,397 lldb::eAccessPublic, 0);398 399 if (si_errno_then_code) {400 ast->AddFieldToRecordType(siginfo_type, "si_errno", int_type,401 lldb::eAccessPublic, 0);402 ast->AddFieldToRecordType(siginfo_type, "si_code", int_type,403 lldb::eAccessPublic, 0);404 } else {405 ast->AddFieldToRecordType(siginfo_type, "si_code", int_type,406 lldb::eAccessPublic, 0);407 ast->AddFieldToRecordType(siginfo_type, "si_errno", int_type,408 lldb::eAccessPublic, 0);409 }410 411 // the structure is padded on 64-bit arches to fix alignment412 if (triple.isArch64Bit())413 ast->AddFieldToRecordType(siginfo_type, "__pad0", int_type,414 lldb::eAccessPublic, 0);415 416 // union used to hold the signal data417 CompilerType union_type = ast->CreateRecordType(418 nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "",419 llvm::to_underlying(clang::TagTypeKind::Union), lldb::eLanguageTypeC);420 ast->StartTagDeclarationDefinition(union_type);421 422 ast->AddFieldToRecordType(423 union_type, "_kill",424 ast->CreateStructForIdentifier(llvm::StringRef(),425 {426 {"si_pid", pid_type},427 {"si_uid", uid_type},428 }),429 lldb::eAccessPublic, 0);430 431 ast->AddFieldToRecordType(432 union_type, "_timer",433 ast->CreateStructForIdentifier(llvm::StringRef(),434 {435 {"si_tid", int_type},436 {"si_overrun", int_type},437 {"si_sigval", sigval_type},438 }),439 lldb::eAccessPublic, 0);440 441 ast->AddFieldToRecordType(442 union_type, "_rt",443 ast->CreateStructForIdentifier(llvm::StringRef(),444 {445 {"si_pid", pid_type},446 {"si_uid", uid_type},447 {"si_sigval", sigval_type},448 }),449 lldb::eAccessPublic, 0);450 451 ast->AddFieldToRecordType(452 union_type, "_sigchld",453 ast->CreateStructForIdentifier(llvm::StringRef(),454 {455 {"si_pid", pid_type},456 {"si_uid", uid_type},457 {"si_status", int_type},458 {"si_utime", clock_type},459 {"si_stime", clock_type},460 }),461 lldb::eAccessPublic, 0);462 463 ast->AddFieldToRecordType(464 union_type, "_sigfault",465 ast->CreateStructForIdentifier(llvm::StringRef(),466 {467 {"si_addr", voidp_type},468 {"si_addr_lsb", short_type},469 {"_bounds", sigfault_bounds_type},470 }),471 lldb::eAccessPublic, 0);472 473 ast->AddFieldToRecordType(474 union_type, "_sigpoll",475 ast->CreateStructForIdentifier(llvm::StringRef(),476 {477 {"si_band", band_type},478 {"si_fd", int_type},479 }),480 lldb::eAccessPublic, 0);481 482 // NB: SIGSYS is not present on ia64 but we don't seem to support that483 ast->AddFieldToRecordType(484 union_type, "_sigsys",485 ast->CreateStructForIdentifier(llvm::StringRef(),486 {487 {"_call_addr", voidp_type},488 {"_syscall", int_type},489 {"_arch", uint_type},490 }),491 lldb::eAccessPublic, 0);492 493 ast->CompleteTagDeclarationDefinition(union_type);494 ast->AddFieldToRecordType(siginfo_type, "_sifields", union_type,495 lldb::eAccessPublic, 0);496 497 ast->CompleteTagDeclarationDefinition(siginfo_type);498 return siginfo_type;499}500 501static std::string GetDescriptionFromSiginfo(lldb::ValueObjectSP siginfo_sp) {502 if (!siginfo_sp)503 return "";504 505 lldb_private::LinuxSignals linux_signals;506 int code = siginfo_sp->GetChildMemberWithName("si_code")->GetValueAsSigned(0);507 int signo =508 siginfo_sp->GetChildMemberWithName("si_signo")->GetValueAsSigned(-1);509 510 auto sifields = siginfo_sp->GetChildMemberWithName("_sifields");511 if (!sifields)512 return linux_signals.GetSignalDescription(signo, code);513 514 // declare everything that we can populate later.515 std::optional<lldb::addr_t> addr;516 std::optional<lldb::addr_t> upper;517 std::optional<lldb::addr_t> lower;518 std::optional<uint32_t> pid;519 std::optional<uint32_t> uid;520 521 // The negative si_codes are special and mean this signal was sent from user522 // space not the kernel. These take precedence because they break some of the523 // invariants around kernel sent signals. Such as SIGSEGV won't have an524 // address.525 if (code < 0) {526 auto sikill = sifields->GetChildMemberWithName("_kill");527 if (sikill) {528 auto pid_sp = sikill->GetChildMemberWithName("si_pid");529 if (pid_sp)530 pid = pid_sp->GetValueAsUnsigned(-1);531 auto uid_sp = sikill->GetChildMemberWithName("si_uid");532 if (uid_sp)533 uid = uid_sp->GetValueAsUnsigned(-1);534 }535 } else {536 537 switch (signo) {538 case SIGILL:539 case SIGFPE:540 case SIGBUS: {541 auto sigfault = sifields->GetChildMemberWithName("_sigfault");542 if (!sigfault)543 break;544 545 auto addr_sp = sigfault->GetChildMemberWithName("si_addr");546 if (addr_sp)547 addr = addr_sp->GetValueAsUnsigned(-1);548 break;549 }550 case SIGSEGV: {551 auto sigfault = sifields->GetChildMemberWithName("_sigfault");552 if (!sigfault)553 break;554 555 auto addr_sp = sigfault->GetChildMemberWithName("si_addr");556 if (addr_sp)557 addr = addr_sp->GetValueAsUnsigned(-1);558 559 auto bounds_sp = sigfault->GetChildMemberWithName("_bounds");560 if (!bounds_sp)561 break;562 563 auto addr_bnds_sp = bounds_sp->GetChildMemberWithName("_addr_bnd");564 if (!addr_bnds_sp)565 break;566 567 auto lower_sp = addr_bnds_sp->GetChildMemberWithName("_lower");568 if (lower_sp)569 lower = lower_sp->GetValueAsUnsigned(-1);570 571 auto upper_sp = addr_bnds_sp->GetChildMemberWithName("_upper");572 if (upper_sp)573 upper = upper_sp->GetValueAsUnsigned(-1);574 575 break;576 }577 default:578 break;579 }580 }581 582 return linux_signals.GetSignalDescription(signo, code, addr, lower, upper,583 pid, uid);584}585 586lldb::StopInfoSP PlatformLinux::GetStopInfoFromSiginfo(Thread &thread) {587 ValueObjectSP siginfo_sp = thread.GetSiginfoValue();588 if (!siginfo_sp)589 return {};590 auto signo_sp = siginfo_sp->GetChildMemberWithName("si_signo");591 auto sicode_sp = siginfo_sp->GetChildMemberWithName("si_code");592 if (!signo_sp || !sicode_sp)593 return {};594 595 std::string siginfo_description = GetDescriptionFromSiginfo(siginfo_sp);596 if (siginfo_description.empty())597 return StopInfo::CreateStopReasonWithSignal(598 thread, signo_sp->GetValueAsUnsigned(-1));599 600 return StopInfo::CreateStopReasonWithSignal(601 thread, signo_sp->GetValueAsUnsigned(-1), siginfo_description.c_str(),602 sicode_sp->GetValueAsUnsigned(0));603}604