Login
Username:

Password:

Remember me



Lost Password?

Register now!

Sections

Who's Online
52 user(s) are online (39 user(s) are browsing Forums)

Members: 1
Guests: 51

flash, more...

Support us!

Headlines

Forum Index


Board index » All Posts (kas1e)




Re: AmiPDF ?
Home away from home
Home away from home


@Maijestro
Check also my old port of VPDF from Morphos (on os4depot) should be fast enough too.

Quote:

can I instruct AmigaOs4.1 to always open PDF files with RNOPDF as soon as I use them?


In system:prefs/Env-Archive/Sys/ find the one for pdf (can't check now, but this probably def_pdf.info) and change in the tooltypes for binary you need.

Join us to improve dopus5!
AmigaOS4 on youtube
Go to top


Re: clib2 vs newlib perfomance issues
Home away from home
Home away from home


@all
Andrea did some good bunch of optimization including not calling check_abort() when not need it, as well as instead of line-buffering usefull buffering, and all f* (fwrite,fputs, etc) based functions now on the same speed level as newlib, same as pure puts(), and all vrptinf/string-formatting based ones also gain some speed , while still not as good as newlib because of this FILE * crap, but at least much better even with this FILE * left from clib2.

Join us to improve dopus5!
AmigaOS4 on youtube
Go to top


Re: Snork: New Tracing Tool for AmigaOS 4
Home away from home
Home away from home


@msteed
Design question: Should we allow any format specifier for any argument, or restrict them to a specific set? If we allow any, users could easily use %s for a decimal value and create a mess (though we can already detect invalid strings and limit their size). Allowing all format specifiers feels logical: users can choose what they want—pointers, hex, decimal, strings, etc.—but it requires caution. Alternatively, we could limit specifiers to match the types expected by the patched function. But then, what's the point of setting them if they're fixed to the function's expected types? In that case, we wouldn't need scripting—just a list of functions with the ability to mark unneeded args with "-".

IMHO, we should support the same range of printf-style format specifiers and let users decide what they want to see. What do you think?

Also, I'm unsure whether we should provide an option to enable/disable "task/process" info and "return type," or just always show the task name/address and return type by default and no worry about disabling. What do you think?

Join us to improve dopus5!
AmigaOS4 on youtube
Go to top


Re: Snork: New Tracing Tool for AmigaOS 4
Home away from home
Home away from home


@msteed
Quote:

I wrote my original comment back before you switched to IPC. Now that you're copying all the arguments anyway, you're right, it's no big deal to wait until the call returns so you can report the return code as well. Snork is getting better and better!


In small tests even without IPC taking result and then print it with arguments works, but yea, after calling original function arguments can easy die, so copy need it..

Join us to improve dopus5!
AmigaOS4 on youtube
Go to top


Re: X5000 maybe dying :(
Home away from home
Home away from home


My x5k/020 one always 74-78 for all the ten years.

Join us to improve dopus5!
AmigaOS4 on youtube
Go to top


Re: Snork: New Tracing Tool for AmigaOS 4
Home away from home
Home away from home


@msteed
btw,

Quote:

It would be nice to be able to see the return value from the patched calls, though that will be a bit more complex as you need to report twice, once before the call and once after.

There are some functions that return 64-bit values too, if you get to the point of reporting on return codes.


But i can just call original function before the log, so to have result as well at the same time, i mean something like:


// Wrapper function for patching Open
static BPTR Patched_Open(struct DOSIFace *SelfCONST_STRPTR nameLONG accessMode) {
    
BPTR result 0;
    
// Call the original function
    
if (Original_Open) {
        
result Original_Open(SelfnameaccessMode);
    }
    
// Log arguments and return value
    
LogPatchedFunction(RETURN_BPTRresult"IDOS->Open(name='%s', accessMode=%ld)"name name "NULL"accessModeresult);
    return 
result;
}



or for int64 return:

// Wrapper function for patching GetFilePosition
static int64 Patched_GetFilePosition(struct DOSIFace *SelfBPTR fh) {
    
int64 result 0;
    
// Call the original function
    
if (Original_GetFilePosition) {
        
result Original_GetFilePosition(Selffh);
    }
    
// Log arguments and return value
    
LogPatchedFunction(RETURN_INT64result"IDOS->GetFilePosition(Self=0x%lx, fh=0x%lx)", (uint32)Selffh);
    return 
result;
}


And log it like:

uint32 VARARGS68K LogPatchedFunction(uint32 returnTypeint64 returnValue, const char *format, ...) {
    
char buffer[512];
    
va_list args;
    
va_startlinear(argsformat);
    
APTR data va_getlinearva(argsAPTR);
    
IExec->RawDoFmt(formatdataNULLbuffer);
    if (
returnType != RETURN_NONE) {
        
char returnBuffer[64];
        switch (
returnType) {
            case 
RETURN_BPTR: {
                
// Use lower 32 bits for BPTR
                
int32 value = (int32)(returnValue 0xFFFFFFFF);
                
IExec->RawDoFmt(" return=0x%lx\n", &valueNULLreturnBuffer);
                break;
            }
            case 
RETURN_INT32: {
                
// Use lower 32 bits for int32
                
int32 value = (int32)(returnValue 0xFFFFFFFF);
                
IExec->RawDoFmt(" return=%ld\n", &valueNULLreturnBuffer);
                break;
            }
            case 
RETURN_LONG: {
                
// Use lower 32 bits for LONG
                
int32 value = (int32)(returnValue 0xFFFFFFFF);
                
IExec->RawDoFmt(" return=%ld\n", &valueNULLreturnBuffer);
                break;
            }
            case 
RETURN_INT64: {
                
// Use full int64
                
IExec->RawDoFmt(" return=%lld\n", &returnValueNULLreturnBuffer);
                break;
            }
            case 
RETURN_BOOL: {
                
// Use lower 32 bits for BOOL (normalized to 0 or 1)
                
int32 value = (int32)(returnValue 0xFFFFFFFF);
                
IExec->RawDoFmt(" return=%ld\n", &valueNULLreturnBuffer);
                break;
            }
            default:
                
returnBuffer[0] = '\0'// No return value if type is unknown
                
break;
        }
        
// Append return value to the log
        
IExec->DebugPrintF("%s%s"bufferreturnBuffer);
    } else {
        
IExec->DebugPrintF("%s"buffer);
    }
    
va_end(args);
    return 
0;
}


Something of that sort..

So it will be:

IIntuition->SetWindowTitles(Self=0x6FFFFC00window=0x600A52E0windowTitle=AmigaShellscreenTitle=0xFFFFFFFF)
IDOS->Open(name='NIL:'accessMode=1005) return=0x183F26EC
IDOS
->Open(name='console:'accessMode=1006) return=0x183F2722
IDOS
->Open(name='Env:Sys/console.prefs'accessMode=1005) return=0x17FE285C
IDOS
->ChangeFilePosition(file=0x188092F2position=10offset=-1) return=0
IDOS
->GetFilePosition(Self=0x6FFA05D0fh=0x188092F2) return=0
IDOS
->ChangeFilePosition(file=0x1880935Eposition=10offset=-1) return=1
IDOS
->GetFilePosition(Self=0x6FFA05D0fh=0x1880935E) return=10


Edited by kas1e on 2025/7/2 10:52:10
Edited by kas1e on 2025/7/2 11:12:43
Join us to improve dopus5!
AmigaOS4 on youtube
Go to top


Re: clib2 vs newlib perfomance issues
Home away from home
Home away from home


@joerg
Quote:

You only have 2 options:
- Re-implement all clib4 parts from scratch and remove any code from clib4, not only the I/O related parts, which were based on clib2 sources.


Probably only that one to go.


Quote:

- Throw away the whole junk and restart from scratch, porting a usable C library like newlib, uClib, AROS C library, etc., (a glibc port is next to impossible, a NetBSD libc port way too much work, and my OS4 port of ixemul incomplete and too complicated to install for casual users...), instead.


There only newlib and uClib can be pretended for, because AROS one for sure will have more bugs and there the same no developers mostly (just a few as on os4), and it will be surely full of ifdefs of any sort because of too much different platforms support. We get rid of clib2 just to not have anymore os3/mos ifdefs in which no one use anymore.. But then, its anyway too late to change the route for a complete new rewrite: Andrea already spend a year or two in clib4, so he for sure will start nothing new, he currently have no time to deal with replacing FILE * clib2 crap.

From another side, maybe someone on payment basis want to replace FILE * crap in clib4 on proper newlibs one or uClib one ?

Join us to improve dopus5!
AmigaOS4 on youtube
Go to top


Re: Snork: New Tracing Tool for AmigaOS 4
Home away from home
Home away from home


@msteed
Also another reason to switch to IPC: if i just call DebugPrintF from patching function, it sometime can overlap output. With IPC it wait for message, and then print it.

Join us to improve dopus5!
AmigaOS4 on youtube
Go to top


Re: clib2 vs newlib perfomance issues
Home away from home
Home away from home


@George
Quote:

And what if you redirect output to different place. Like some file in RAM: or to NIL:


I doing all tests being in RAM: with >1 redirect, but retested again, and be it redirected to file, to NIL - all the same for original test case : ~19seconds.

Then tried "255 128 0" with "n" : 13 seconds
Then tried "255 128 0" without "n" : 13 seconds too

Join us to improve dopus5!
AmigaOS4 on youtube
Go to top


Re: clib2 vs newlib perfomance issues
Home away from home
Home away from home


@joerg
Quote:

Just browsed the clib4 sources a bit, and there is still a lot, way too much, crap from clib2 remaining.
Very simple example:
https://github.com/AmigaLabs/clib4/blob/master/library/stdio/lock.c
Just replacing the old, and probably only used for the AmigaOS 1.x-3.x compatibility of clib2, semaphores (based on Forbid()/Permit()!) by OS4 mutexes (based on atomic increment/decrement instructions) should result in a noticeable speed improvement.


Andrea tried to change it all on mutexes : https://github.com/AmigaLabs/clib4/commits/mutexes/ It change a shit :) And i really mean it : no single speed up. Same slow stuff for fwrite(), printf(), puts() and sprintf().

But what were found that if we commented out for example in fwrite.c, check_abourt, lock/unlock, we then gain a bit : like for fwrite it was 13s for test case, and with commented check_abort/lock/unlock start to be 8. Of course nothing mostly, as newlib gives 0.5s on same test, but still something to think about..

Join us to improve dopus5!
AmigaOS4 on youtube
Go to top


Re: Snork: New Tracing Tool for AmigaOS 4
Home away from home
Home away from home


@Joerg
Quote:

and only a single, pre-allocated memory buffer per patched function isn't enough either: The (patched) functions might be called by different tasks at the same time.

How can i know how much buffers i need then if there can be any amount of diffent tasks calling for example allocvec() (probably lots at the same time) ?

@msteed
About 64bit issue: i simple create patch_exceptions.c in which patch by hands functions which not fits into generic_patch(). At moment there just 6 from dos.library using mixed 32/64bits args, intuitions ones as far as i see all fits into 32bit way.

Join us to improve dopus5!
AmigaOS4 on youtube
Go to top


Re: Snork: New Tracing Tool for AmigaOS 4
Home away from home
Home away from home


@msteed
Quote:

Typically, your current approach -- doing as little as possible in the patch, and postponing the formatting and output to Snork itself -- is the recommended way to handle such things. But I wonder if in this case your original approach -- doing everything, including the DebugPrintF(), in the patch -- isn't a better idea.


I switched to IPC only because I started losing strings (some had garbage when they shouldn't). Maybe it was a side effect of a bug or something else, but once I began copying strings and tags in the patch and sending them via messages, the bug disappeared. But of course, this means I now have more code to handle, like first copying, then parsing, and overall it’s starting to be a bit too much, but still probably safer...

Quote:

One drawback to the current approach is that logging the function call is asynchronous to the function call itself- by the time Snork gets the message and outputs the log, the call has already occurred. So if the call crashes due to a bad argument, the crash occurs before the call can be logged (and if the crash takes down the system, the log will never be written).

A bigger problem comes up when you start logging exec.library calls. I presume you allocate memory in the patch to hold all the copies of arguments, and memory allocation can break a Forbid() that might be in effect when Exec is called. It looks like that can be prevented by using the AVT_Wait, FALSE tag with AllocVecTags().


Yes, for copying strings and tags, I use AllocVecTags, and currently my GenericPatch function and SendIPCMessage function look like this:

Patching function:

void GenericPatch(struct Interface *Selfint watchIndexuint32 args[MAX_PARAMS]) {
    if (
watchIndex || watchIndex >= watchCount || !watches[watchIndex].origFunc || 
        !
watches[watchIndex].iface || Self != watches[watchIndex].iface) {
        
IExec->DebugPrintF("Invalid watchIndex or interface mismatch: watchIndex=%d\n"watchIndex);
        return;
    }
    
    
struct Watch *watch = &watches[watchIndex];

    
// Prepare parameter types for IPC message
    
char paramTypes[MAX_PARAMS] = {0};
    for (
int i 0watch->paramCount && MAX_PARAMSi++) {
        
paramTypes[i] = watch->params[i].type;
    }

    
// Handle process filter and task info
    
if (showProcessName || showTaskInfo) {
        
char taskName[256];
        
struct Process *proc = (struct Process *)IExec->FindTask(NULL);
        
Get_Name(taskNamesizeof(taskName), proc);
        if (!
showProcessName || strcmp(taskNameshowProcessName) == 0)
            
SendIPCMessage(watchIndexargswatch->libNamewatch->funcNameparamTypes
                           
showTaskInfo taskName NULLshowTaskInfo ? (uint32)proc 0);
    } else {
        
SendIPCMessage(watchIndexargswatch->libNamewatch->funcNameparamTypesNULL0);
    }


    
// Call the original function with the appropriate number of parameters        
    
typedef void (*FuncPtr)(struct Interface *, ...);
    
FuncPtr origFunc = (FuncPtr)watch->origFunc;
    switch (
watch->paramCount) {
        case 
0origFunc(Self); break;
        case 
1origFunc(Selfargs[0]); break;
        case 
2origFunc(Selfargs[0], args[1]); break;
        case 
3origFunc(Selfargs[0], args[1], args[2]); break;
        case 
4origFunc(Selfargs[0], args[1], args[2], args[3]); break;
        case 
5origFunc(Selfargs[0], args[1], args[2], args[3], args[4]); break;
        case 
6origFunc(Selfargs[0], args[1], args[2], args[3], args[4], args[5]); break;
        case 
7origFunc(Selfargs[0], args[1], args[2], args[3], args[4], args[5], args[6]); break;
        case 
8origFunc(Selfargs[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]); break;
        case 
9origFunc(Selfargs[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]); break;
        case 
10origFunc(Selfargs[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9]); break;
        case 
11origFunc(Selfargs[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10]); break;
        default:
            
IExec->DebugPrintF("Debug: Unsupported parameter count %ld\n"watch->paramCount);
            break;
    }
}



SendIPCMessage():

void SendIPCMessage(int watchIndexuint32 args[MAX_PARAMS], const char *libName, const char *funcName, const char paramTypes[MAX_PARAMS], const char *taskNameuint32 taskAddr) {
    if (!
ipcPort) {
        
IExec->DebugPrintF("IPC port not initialized!\n");
        return;
    }
    
struct IPCMessage *ipcMsg IExec->AllocVecTags(sizeof(struct IPCMessage), 
                                                    
AVT_TypeMEMF_PRIVATE
                                                    
AVT_ClearWithValue0
                                                    
TAG_END);
    if (!
ipcMsg) {
        
IExec->DebugPrintF("Failed to allocate IPC message!\n");
        return;
    }

    
ipcMsg->watchIndex watchIndex;
    
IExec->CopyMem(argsipcMsg->argssizeof(ipcMsg->args));
    
IUtility->Strlcpy(ipcMsg->libNamelibNamesizeof(ipcMsg->libName));
    
IUtility->Strlcpy(ipcMsg->funcNamefuncNamesizeof(ipcMsg->funcName));
    
IExec->CopyMem(paramTypesipcMsg->paramTypesMAX_PARAMS);

    
// Set task name and address only if taskName is provided
    
if (taskName) {
        
IUtility->Strlcpy(ipcMsg->taskNametaskNamesizeof(ipcMsg->taskName));
        
ipcMsg->taskAddr taskAddr;
    } else {
        
ipcMsg->taskName[0] = '\0'// Set to empty string (equivalent to NULL)
        
ipcMsg->taskAddr 0;
    }

    
// Copy string parameters
    
ipcMsg->stringParamCount 0;
    for (
int i 0MAX_PARAMS && paramTypes[i] && ipcMsg->stringParamCount MAX_STRING_PARAMSi++) {
        if (
paramTypes[i] == 's') {
            const 
char *str = (const char *)args[i];
            if (
str) {
                
IUtility->Strlcpy(ipcMsg->stringParams[ipcMsg->stringParamCount], strMAX_STRING_LENGTH);
                
ipcMsg->args[i] = (uint32)ipcMsg->stringParams[ipcMsg->stringParamCount];
                
ipcMsg->stringParamCount++;
            }
        }
    }

    
// Copy tag lists
    
ipcMsg->tagItemCount 0;
    
ipcMsg->tagStringParamCount 0;
    for (
int i 0MAX_PARAMS && paramTypes[i]; i++) {
        if (
paramTypes[i] == 't') {
            
struct TagItem *tags = (struct TagItem *)args[i];
            if (
tags) {
                
int tagCount 0;
                
int moreCount 0;
                while (
tags[tagCount].ti_Tag != TAG_END && tags[tagCount].ti_Tag != TAG_DONE && 
                       
tagCount MAX_TAG_ITEMS && ipcMsg->tagItemCount MAX_TAG_ITEMS && 
                       
moreCount 10) {
                    if (
tags[tagCount].ti_Tag == TAG_IGNORE) {
                        
tagCount++;
                        continue;
                    }
                    if (
tags[tagCount].ti_Tag == TAG_MORE) {
                        if (
tags[tagCount].ti_Data && moreCount 10) {
                            
tags = (struct TagItem *)tags[tagCount].ti_Data;
                            
tagCount 0;
                            
moreCount++;
                            continue;
                        }
                        break;
                    }
                    if (
tags[tagCount].ti_Tag == TAG_SKIP) {
                        
uint32 skipCount tags[tagCount].ti_Data;
                        
tagCount += skipCount 1;
                        if (
tagCount >= MAX_TAG_ITEMS) break;
                        continue;
                    }
                    
// Check if the tag is a string type
                    
const struct TagInfo *info findTagInfoForTag(tags[tagCount].ti_TaglibName);
                    if (
info && info->Type == 's' && tags[tagCount].ti_Data && 
                        
ipcMsg->tagStringParamCount MAX_TAG_STRING_PARAMS) {
                        
// Copy string to tagStringParams
                        
IUtility->Strlcpy(ipcMsg->tagStringParams[ipcMsg->tagStringParamCount], 
                                          (const 
char *)tags[tagCount].ti_DataMAX_STRING_LENGTH);
                        
ipcMsg->tagItems[ipcMsg->tagItemCount].ti_Tag tags[tagCount].ti_Tag;
                        
ipcMsg->tagItems[ipcMsg->tagItemCount].ti_Data = (uint32)ipcMsg->tagStringParams[ipcMsg->tagStringParamCount];
                        
ipcMsg->tagStringParamCount++;
                    } else {
                        
// Copy tag as-is
                        
ipcMsg->tagItems[ipcMsg->tagItemCount] = tags[tagCount];
                    }
                    
ipcMsg->tagItemCount++;
                    
tagCount++;
                    if (
ipcMsg->tagItemCount >= MAX_TAG_ITEMS) break;
                }
                if (
ipcMsg->tagItemCount 0) {
                    if (
ipcMsg->tagItemCount MAX_TAG_ITEMS) {
                        
ipcMsg->tagItems[ipcMsg->tagItemCount].ti_Tag TAG_END;
                        
ipcMsg->tagItemCount++;
                    }
                    
ipcMsg->args[i] = (uint32)ipcMsg->tagItems;
                }
            }
        }
    }

    
ipcMsg->msg.mn_Node.ln_Type NT_MESSAGE;
    
ipcMsg->msg.mn_Length sizeof(struct IPCMessage);
    
ipcMsg->msg.mn_ReplyPort NULL;

    
IExec->PutMsg(ipcPort, (struct Message *)ipcMsg);
}


And then, after I copy it all, I have to reparse and print it, so it's like double the work...

But for now I'm facing another problem: 64-bit arguments for some dos.library functions. The issue is:

Currently, all my patching code, wrappers for functions, etc., are using uint32/int32. That's everywhere, and all arguments are treated like this too (bytes, words, etc., are treated as longs, so int32, no problems there; strings and pointers fit into int32 as well). But then, dos.library has six functions that allow some arguments to be int64:


watch=dos,ChangeFilePosition,file=%lp,position=%ld,offset=%ld                                                  // file (BPTR), position (int64), offset (int32)
watch=dos,ChangeFileSize,fh=%lp,pos=%ld,mode=%ld                                                               // fh (BPTR), pos (int64), mode (int32)
watch=dos,DoPkt64,sendport=%lp,type=%ld,arg1=%ld,arg2=%ld,arg3=%ld,arg4=%ld,arg5=%ld                           // sendport (struct MsgPort *), type (int32), arg1 (int32), arg2 (int64), arg3 (int32), arg4 (int32), arg5 (int64)
watch=dos,PRIVATEDoPkt64,sendport=%lp,type=%ld,arg1=%ld,arg2=%ld,arg3=%ld,arg4=%ld,arg5=%ld                    // sendport (struct MsgPort *), type (int32), arg1 (int32), arg2 (int64), arg3 (int32), arg4 (int32), arg5 (int64)
watch=dos,LockRecord,fh=%lp,offset=%ld,length=%ld,mode=%ld,timeout=%ld                                         // fh (BPTR), offset (int64), length (int64), mode (uint32), timeout (uint32)
watch=dos,UnLockRecord,fh=%lp,offset=%ld,length=%ld                                                            // fh (BPTR), offset (int64), length (int64)


Now, if I patch those functions with my generic patch, which expects all arguments to be int32, I'll just get bugs because an int64 takes up two int32 slots, causing memory shifts, crashes, and other issues. I see that I need to handle int64 as two int32s in all cases, but that means changing GenericPatch, SendIPCMessage, and the logger to always skip two int32s when encountering an int64, and it’s starting to feel like a mess.

If I change everything in the code (wrappers, GenericPatch, etc.) to use int64, I’ll run into problems with int32 arguments for the same reasons.

So, for now, I’m thinking about how to solve this one...

Join us to improve dopus5!
AmigaOS4 on youtube
Go to top


Re: DumbPad v03
Home away from home
Home away from home


@Maijestro
D&D were added in v0.2, check release notes :)
And yeah, i working on, just not ready for next beta

Join us to improve dopus5!
AmigaOS4 on youtube
Go to top


Re: Introducing the Rear Window blog
Home away from home
Home away from home


@trixie
Quote:

Now on the Rear Window blog, my personal manifesto for the summer. Enjoy reading!


That's how I think for years, keeping me away from being disappointed by anything. We use what we already have, and if there are updates - cool, if not, I know what I do and with what. Waiting for anything from leaders or hoping for any promises is the way to the trap. Let them do what they think and can do, but it shouldn't reflect on you in any case.

Join us to improve dopus5!
AmigaOS4 on youtube
Go to top


Re: Snork: New Tracing Tool for AmigaOS 4
Home away from home
Home away from home


@joerg
Quote:

to add support for international chars, for example the default ISO 8859-15 ones.
Unprintable control chars on AmigaOS, in any supported 8 bit charset, are only 0-31 and 127-159.


Good catch , thanks !

Btw, what is the best way to follow if we need to parse data in a patch ? At fist, i just doing simple parsing inside of the patch, and then print it before calling original function. Then after , i add some simple IPC via PutMsg() (from patch) /GetMsg() (in main).

At first i tried to simple send what i have to the main, but find out that strings and other data simple died offten (because patch is done, memory changes, but i tried to handle it in the main which is point on whatever else). Because of that i had to copy in the patch before putmsg whole set : libname, functionname, doing findtaks(null), copy strings and tags, and then send this instead. For copy i use IExec->CopyMem/IUtility->Strlcpy (that for libname, funcname and strings), and for tags i simple do simple loop copy.

The question i had now , is it correct way of doing things. I mean, for speed and for being correct at all. As i doing dynamic copy for each patching function, i do not need locks and mutexes, but not sure shouldn't i somehow protect it or not ?


Edited by kas1e on 2025/6/27 19:58:44
Join us to improve dopus5!
AmigaOS4 on youtube
Go to top


Re: Snork: New Tracing Tool for AmigaOS 4
Home away from home
Home away from home


@msteed
Quote:

For dealing with buggy pointers to something that's not a NUL-delimited string, I was thinking of something simple, like limiting the length that's printed to something reasonable, so you won't potentially get thousands of random characters until it happens to encounter a NUL.

In addition, you could filter the string to turn unprintable characters into periods (or some other character), so you won't possibly print an escape code or control character that interferes with the display of the snooped data. That would require making a copy of the string, since you don't want to alter the original.


For now i limited string to 256 chars, + checking on null and 0xffffffff, + checked on format characters so to printf them as it, without taking as formatting symbols, cheking on fancy characters and replace them to (so printable ASCII character only) , etc. So before show the string i just do this:

// Create a safe, quoted string representation for logging
void safe_string_representation(const char *inputchar *outputsize_t output_size) {
    if (!
input) {
        
strncpy(output"NULL"output_size 1);
        
output[output_size 1] = '\0';
        return;
    }
    if (
input == (CONST_STRPTR)0xFFFFFFFF) {
        
strncpy(output"0xFFFFFFFF"output_size 1);
        
output[output_size 1] = '\0';
        return;
    }
    
size_t j 0;
    if (
output_size 1) {
        
output[j++] = '"';
    }
    for (
size_t i 0input[i] && output_size 2i++) {
        if (
input[i] == '%') {
            if (
output_size 3) {
                
output[j++] = '%';
                
output[j++] = '%';
            }
        } else if (
input[i] == '"' || input[i] == '\\') {
            if (
output_size 3) {
                
output[j++] = '\\';
                
output[j++] = input[i];
            }
        } else if (
input[i] >= 32 && input[i] <= 126) {
            
output[j++] = input[i];
        } else {
            if (
output_size 3) {
                
output[j++] = '?';
            }
        }
    }
    if (
output_size 1) {
        
output[j++] = '"';
    }
    
output[j] = '\0';
    if (
>= output_size 1) {
        
output[output_size 1] = '\0';
    }
}


And then :

char safe_str[256];
                        
safe_string_representation((const char *)tag->ti_Datasafe_strsizeof(safe_str));
                        
IExec->DebugPrintF("  %s = %s\n"info->Namesafe_str);


Should be enough imho even without IExec->TypeOfMem() ?

Join us to improve dopus5!
AmigaOS4 on youtube
Go to top


Re: Snork: New Tracing Tool for AmigaOS 4
Home away from home
Home away from home


@all
Thanks for suggestions !

@Javier
Quote:

Just when you CTRL+C Snork just show a simple "Snork ended" on Shell/CLI (and maybe to serial outoput too).


Added, now it says start/end on both serial and console.

@msteed
Quote:

It would also be nice if it showed the name of the program making the call like OS4 Snoopy does, so you can see which calls are made by the program being debugged


Done, now output looks like this (some simple trace of few dos functions):

...
Task/ProcessWorkbench (0x62E0AB30) --> IDOS->Open(name="LOCALE:Catalogs/english_UTF-8/Sys/libs.catalog",accessMode=1005)
Task/ProcessWorkbench (0x62E0AB30) --> IDOS->AllocDosObject(type=0,tags=0x00000000)
Task/ProcessWorkbench (0x62E0AB30) --> IDOS->PRIVATEDoPkt32(port=0x6FDF5450,action=1005,arg1=411674462,arg2=415205712,arg3=409172995,arg4=0,arg5=409172995,arg6=0,arg7=0)
Task/ProcessWorkbench (0x62E0AB30) --> IDOS->PRIVATEDoPkt32(port=0x6FDF5450,action=1005,arg1=411674462,arg2=412428724,arg3=409172995,arg4=0,arg5=409172995,arg6=0,arg7=0)
Task/ProcessWorkbench (0x62E0AB30) --> IDOS->FreeDosObject(type=0,ptr=0x62269D78)
Task/ProcessWorkbench (0x62E0AB30) --> IDOS->IoErr()
Task/ProcessWorkbench (0x62E0AB30) --> IDOS->Open(name="LOCALE:Catalogs/english_US_ASCII/Sys/libs.catalog",accessMode=1005)
Task/ProcessWorkbench (0x62E0AB30) --> IDOS->AllocDosObject(type=0,tags=0x00000000)
Task/ProcessWorkbench (0x62E0AB30) --> IDOS->PRIVATEDoPkt32(port=0x6FDF5450,action=1005,arg1=411674462,arg2=415205712,arg3=409172995,arg4=0,arg5=409172995,arg6=0,arg7=0)
Task/ProcessWorkbench (0x62E0AB30) --> IDOS->PRIVATEDoPkt32(port=0x6FDF5450,action=1005,arg1=411674462,arg2=412428724,arg3=409172995,arg4=0,arg5=409172995,arg6=0,arg7=0)
Task/ProcessWorkbench (0x62E0AB30) --> IDOS->FreeDosObject(type=0,ptr=0x62269D78)
Task/ProcessWorkbench (0x62E0AB30) --> IDOS->IoErr()
Task/Processdopus_clock (0x61F8C1F0) --> IDOS->DateStamp(date=0x61A2ED44)
Task/ProcessELF Collector (0x6FDB57A0) --> IDOS->Delay(timeout=25)
Task/ProcessELF Collector (0x6FDB57A0) --> IDOS->Delay(timeout=25)
Task/Processdopus_clock (0x61F8C1F0) --> IDOS->DateStamp(date=0x61A2ED44)
Task/ProcessELF Collector (0x6FDB57A0) --> IDOS->Delay(timeout=25)
Task/ProcessELF Collector (0x6FDB57A0) --> IDOS->Delay(timeout=25)
Task/Processdopus_clock (0x61F8C1F0) --> IDOS->DateStamp(date=0x61A2ED44)
Task/ProcessELF Collector (0x6FDB57A0) --> IDOS->Delay(timeout=25)
Task/ProcessELF Collector (0x6FDB57A0) --> IDOS->Delay(timeout=25)
Task/Processdopus_clock (0x61F8C1F0) --> IDOS->DateStamp(date=0x61A2ED44)
Task/ProcessELF Collector (0x6FDB57A0) --> IDOS->Delay(timeout=25)
Task/ProcessELF Collector (0x6FDB57A0) --> IDOS->Delay(timeout=25)
Task/Processdopus_clock (0x61F8C1F0) --> IDOS->DateStamp(date=0x61A2ED44)
Task/ProcessELF Collector (0x6FDB57A0) --> IDOS->Delay(timeout=25)
Task/Processsnork (0x62E0A9B0) --> IDOS->Output()
Task/Processsnork (0x62E0A9B0) --> IDOS->IoErr()
Task/Processsnork (0x62E0A9B0) --> IDOS->IoErr()
Task/Processsnork (0x62E0A9B0) --> IDOS->Write(file=0x1839CFA8,buffer=0x60671000,length=51)
...


Also added 3 arguments now :

IDOS->Printf("Usage: %s [--help] [--script=<filename>] [--taskinfo=<yes|no>] [--show=<process name>]\n"argv[0]);
            
IDOS->Printf("  --help                Show this help message and exit\n");
            
IDOS->Printf("  --script=<filename>   Script file to parse (must end with .snork, default: main.snork)\n");
            
IDOS->Printf("  --taskinfo=<yes|no>   Show task/process info (default: yes)\n");
            
IDOS->Printf("  --show=<process name> Log only for specified process name (default: all processes)\n");
            
IDOS->Printf("Note: For process names with spaces, quote the entire argument, e.g., --show=\"ELF Collector\"\n");


So you can 1), enable/disable task names, 2) use any script you wish (default main.snork), 3) have output from any task you want.


For string handling at minimum will do as Joerg says with IExec->TypeOfMem() , better than nothing (for now).

ps. Btw, added also new keyword for template %t - so you can output tags instead of pointer, and then output will looks like this:

Snork started!
Task/ProcessWinFrame 1 Process (0x62907070) --> IDOS->Open(name="NIL:",accessMode=1005)
Task/ProcessWinFrame 1 Process (0x62907070) --> IDOS->CreateNewProc()
tags: (tags=0x61A58EE0)
  
NP_Seglist 0x1BFCF735
  NP_WindowPtr 
0x0
  NP_Error 
0x0
  NP_Path 
0x0
  NP_FreeSeglist 
FALSE
  NP_Input 
0x0
  NP_Output 
0x0
  NP_CloseInput 
FALSE
  NP_CloseOutput 
FALSE
  NP_CurrentDir 
0x0
  NP_ProgramDir 
0x0
  NP_Cli 
TRUE
  SYS_Asynch 
TRUE
  SYS_Input 
0x0
  SYS_Output 
0x0
  SYS_Error 
0x0
  SYS_UserShell 
TRUE
  NP_Path 
0x189539AC
  NP_CopyVars 
TRUE
  NP_Name 
"DuplicateShell"
  
NP_Priority 0
  NP_StackSize 
65536
  NP_ConsolePort 
0x0
  Processed 23 tags
Task
/ProcessDuplicateShell (0x62082830) --> IDOS->Open(name="console:",accessMode=1006)
Task/ProcessNewShell (0x62082830) --> IDOS->CreateNewProc()
tags: (tags=0x61A58100)
  
NP_Seglist 0x1BFCF735
  NP_FreeSeglist 
FALSE
  NP_StackSize 
65528
  NP_Cli 
TRUE
  NP_ProgramDir 
0x0
  NP_CloseInput 
FALSE
  NP_CloseOutput 
FALSE
  NP_CurrentDir 
0x0
  NP_Input 
0x0
  NP_Output 
0x0
  NP_CopyVars 
TRUE
  NP_Name 
"Shell Process"
  
Processed 12 tags


For that had to create a base of the tags for every library (as they can cross, in hope they will not).

And i also move all stuff to IPC now, i.e. in generic_patch just
now send the message and call to original, all loging/parsing happens in main's handleinput.

Join us to improve dopus5!
AmigaOS4 on youtube
Go to top


Re: Tracing of callhookpkt()/callhook() and varargs
Home away from home
Home away from home


@joerg
Quote:

The varargs functions simply call the non-varargs ones, not only in dos but in all OS4 libraries.


Looks so indeed. That what happens when i patch all 3 : CreateNewProc(), CreateNewProcTagList() and CreateNewProcTags(...) and simple call
CreateNewProcTags with 5 tags:


IDOS->CreateNewProcTags(...)
NP_Entry 0x7FFB2500
NP_Name 
amiga1200
NP_FreeSeglist 
0
NP_CloseOutput 
1
NP_Child 
1
IDOS
->CreateNewProcTagList(tags=0x5FDADCC8)
IDOS->CreateNewProc(tags=0x5FDADCC8)


CreateNewProcTagList() is the one i called from patched CreateNewProcTags, and CreateNewProc() seems the one called from TagList one. Because if i simple replace in varargs one to call at end CreateNewProc() one instead of TagList one, then output is:

IDOS->CreateNewProcTags(...)
NP_Entry 0x7FFB2500
NP_Name 
amiga1200
NP_FreeSeglist 
0
NP_CloseOutput 
1
NP_Child 
1
IDOS
->CreateNewProc(tags=0x5FD9CCC8)



Btw, what about Printf(), DebugPrintF(), etc ? They all call VSNPrintf() in end ? But then, user want to know exactly what he call imho, even if after it go over other function (so maybe it need to be patched, logged, and giving control to the one which called for real after) ? Because seeing in log bunch of VSPirntf() while you call for example pure Printf() or DebugPrintF() will make it looks wrong imho.


Edited by kas1e on 2025/6/25 6:48:42
Join us to improve dopus5!
AmigaOS4 on youtube
Go to top


Re: Tracing of callhookpkt()/callhook() and varargs
Home away from home
Home away from home


@all
Can anyone bring some ideas how to patch/trace varargs based functions (such as Tags(...), format strings ones, and those specific rare cases where varargs used but not fits in first 2 categries) ?

I tried to patch for test CreateNewProcTags(...), and can't make it work as it, because it takes (...), i then reparce them via va_* functions, and then i need to call original version, which didn't take (...) anymore but args => crash. I.e:

// Wrapper function for patching CreateNewProcTags
static void VARARGS68K Patched_CreateNewProcTags(struct DOSIFace *Self, ...) {
    
    
va_list args;
    
va_startlinear(argsSelf);
    
struct TagItem *tags va_getlinearva(argsstruct TagItem *);
    
    
Original_CreateNewProcTags(Selftags); // ! Can't! Expected (...)
    
    
va_end(args);
}


That one crashes of course..

I can replace of course call to original by CreateNewProcTagList(tags), and it then works, but then it isn't much "tracer", but "replacer" :) All i need is to simple grab the (...), parce all tags from till TAG_DONE/TAG_END found, print, and return all of them back to original, but of course i can't via a way i do it. But maybe there some other ways how i can do so ? Like some varargs forwarding or so ?


Edited by kas1e on 2025/6/24 11:59:07
Join us to improve dopus5!
AmigaOS4 on youtube
Go to top


Re: NULL, 0xFFFFFFFF and Exec: Real vs QEMU
Home away from home
Home away from home


@jabirulo
Quote:

It's on the autodoc for such "strange" values.

Yeah, read it all yesterday already. Is it only SetWindowTitles allowing -1 or there are more ? I see NULL is acceptable offten, but -1 ?

Join us to improve dopus5!
AmigaOS4 on youtube
Go to top



TopTop
(1) 2 3 4 ... 428 »




Powered by XOOPS 2.0 © 2001-2024 The XOOPS Project